Compare commits
433 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b66701c5d | |||
| 3a8b99db10 | |||
| 6e7cf42831 | |||
| 0e42f977ee | |||
| ef379cdeb3 | |||
| 4886312e43 | |||
| 3a152366d2 | |||
| d920bcb2f4 | |||
| 268a1817ab | |||
| f5c493500f | |||
| 7533f304ff | |||
| 755d4f2388 | |||
| 6884395daa | |||
| 5299b94f9e | |||
| f701787802 | |||
| 0b58e0ae24 | |||
| 03226d1487 | |||
| 534f8c6b99 | |||
| e544a6d2fa | |||
| d696535da5 | |||
| 7e444b7c42 | |||
| 0d377d98a7 | |||
| 5bdbee6dae | |||
| 014374e33e | |||
| 9adb4fbbbc | |||
| 5293766856 | |||
| a40bb3ae4f | |||
| 226c37cfea | |||
| ea8f36dfd2 | |||
| b466cb6b3d | |||
| bb0328137a | |||
| e07974ad2b | |||
| e8bb96b7d0 | |||
| 9bd06dbfcc | |||
| 055b10f7f2 | |||
| 44ca339ee5 | |||
| b6a43787b3 | |||
| 9cb22d9bde | |||
| 68485f8998 | |||
| 9c22c082c0 | |||
| 28d7400304 | |||
| 056d189e0e | |||
| b76eab2363 | |||
| b8a2ac5719 | |||
| c861e40047 | |||
| 20426d001e | |||
| 2eed9fd247 | |||
| a1887356dc | |||
| ef2420f847 | |||
| 6f26475055 | |||
| b9bf6e4521 | |||
| 7e392ff6c3 | |||
| 9e834ebaef | |||
| f96a4ffed3 | |||
| 8e9c0d2b0d | |||
| 33c356b3ec | |||
| c902e8eaa5 | |||
| 1dc8b5894f | |||
| ad285af0fa | |||
| 6621e5c72f | |||
| 969a93cf80 | |||
| f52ee0431c | |||
| a41cfd47a4 | |||
| 0b098687e1 | |||
| 09709dd8e4 | |||
| ef0867a7e7 | |||
| bfa7754ea6 | |||
| a4377bf1a6 | |||
| 9e30f9a346 | |||
| 7878895651 | |||
| fcc940a4d6 | |||
| 036092bb9c | |||
| dcde42c45d | |||
| 5b5bbc2a3d | |||
| 0c1cdc4b63 | |||
| 953c1eddd9 | |||
| 6ae0913aa1 | |||
| 92834ff9b8 | |||
| bfba92de97 | |||
| d37b63f788 | |||
| 63dd26ca1b | |||
| f24d6e224d | |||
| f9a154b36c | |||
| 72d994880b | |||
| fe02bc4631 | |||
| 1fb8e1bbaf | |||
| 96aa355db3 | |||
| 8dfb9c8173 | |||
| 382d3e130e | |||
| a8246621e1 | |||
| 66b6a8aeef | |||
| 93165ad699 | |||
| 2ebb498589 | |||
| 929a780315 | |||
| c7cdd1e1b4 | |||
| 8575a72a22 | |||
| 9d03bec14b | |||
| 7c826ef881 | |||
| ac666b7a1d | |||
| 83a9b993a1 | |||
| fe4fcc7fdf | |||
| a6e40443a4 | |||
| 0a583bd48a | |||
| 96ccce1049 | |||
| 89d0ff5624 | |||
| 2391d11758 | |||
| 902c674ff1 | |||
| 160328a08e | |||
| 9fea869bbc | |||
| c66d7ed489 | |||
| 19d603ba1a | |||
| b30f680549 | |||
| 379dd1f02b | |||
| 38804279e8 | |||
| 3907cd17fe | |||
| 67c69cbec9 | |||
| abc5dd8b92 | |||
| c791de426a | |||
| 4c5d4ac4a4 | |||
| 48c1fcaf93 | |||
| 31594c7a79 | |||
| 8ec3c04a39 | |||
| ba7fecde6f | |||
| 835a915f25 | |||
| 9c16e5ebfa | |||
| 5dc57d2a3e | |||
| fd619cad51 | |||
| 953c0915d1 | |||
| acb1aa8df0 | |||
| b9ef848523 | |||
| b7bc713cd4 | |||
| b966f962c8 | |||
| 698cdc524d | |||
| 448aba0917 | |||
| b813e1fee0 | |||
| 23de430f93 | |||
| 9462bc726d | |||
| 3d2eaeeabb | |||
| a732a676e0 | |||
| d6a8fcda9c | |||
| 3628cd92c9 | |||
| 8d26acbc7e | |||
| 07b971fe92 | |||
| 2a539dc3cc | |||
| 562eb639a2 | |||
| 91dd830a5e | |||
| 18837220f4 | |||
| 3fb9737db4 | |||
| 4d0b5b34ec | |||
| 6af0dbd1da | |||
| 2004148710 | |||
| 1e805be5ad | |||
| 7a25e600b3 | |||
| 1fd7d54715 | |||
| 0575f01f9b | |||
| 43a6e62050 | |||
| 39fb131d95 | |||
| 9533c2440a | |||
| aab2be1fbd | |||
| 448dcbeaa8 | |||
| 29b07b4904 | |||
| cceb7a40bd | |||
| fb4b32359d | |||
| 7ca92cc487 | |||
| 15d612eff6 | |||
| 021c2d14f2 | |||
| 3b85927a90 | |||
| b386388b82 | |||
| 7941b7099f | |||
| 6604d927c5 | |||
| 4fedf05b64 | |||
| fa00f85a31 | |||
| abf5a2d307 | |||
| 8e0000cb0b | |||
| cc27911671 | |||
| b598f1d1db | |||
| d4f10c1d68 | |||
| 1d7ff40d02 | |||
| 72703b36e1 | |||
| ecf7a40010 | |||
| 272e9187d2 | |||
| 69a1f3773c | |||
| 15c97b1cae | |||
| 2660ef59f7 | |||
| 12a06d9dfe | |||
| 6399cd24c8 | |||
| f30b5162e8 | |||
| 229329ae4c | |||
| a3bb5e466d | |||
| 65d893a70b | |||
| e0944e5238 | |||
| b451d4b709 | |||
| 1507e48158 | |||
| 6e7a7ed4a6 | |||
| af4801ac47 | |||
| b748c55d4e | |||
| 84e5bfc286 | |||
| 96bd9ecf49 | |||
| 092851976f | |||
| 9da1f82cca | |||
| 8c60927fe2 | |||
| ec5ef1db56 | |||
| 5dee6dd44f | |||
| aa6f5ad664 | |||
| 201b5cc56f | |||
| 510553a697 | |||
| b81967c9f5 | |||
| fadff7888b | |||
| 24854f9254 | |||
| 8ea7726e81 | |||
| ea32a897b2 | |||
| 5d7a14c5ab | |||
| cad68b8d6c | |||
| 1d125ed97f | |||
| 36d4ec5a72 | |||
| 44981b8621 | |||
| bd68797432 | |||
| 636759789c | |||
| c03a859223 | |||
| b269cdae31 | |||
| 2177a396b9 | |||
| 4c50dd64f4 | |||
| be9d3a48bb | |||
| 37d890c634 | |||
| 6287583f4b | |||
| c7760c6c10 | |||
| 2c0058c477 | |||
| 02fb2e56ca | |||
| 8b2c72eb91 | |||
| 805eb31728 | |||
| 22d4c89e48 | |||
| 28d5ac92b3 | |||
| a2e678587c | |||
| 0ac7bb5f03 | |||
| 7f45cbd5df | |||
| 8ce709bbb4 | |||
| 46db139f79 | |||
| 069c5bf332 | |||
| 54a4653e7d | |||
| ea1f689c71 | |||
| 3d60299b22 | |||
| 4d9dfac812 | |||
| 0012294dc0 | |||
| 5b5063676f | |||
| 833556020d | |||
| 0cdb68bcf3 | |||
| aa00eb70d5 | |||
| a882d10848 | |||
| c03a58ae9a | |||
| 2caf79fba0 | |||
| eda1822653 | |||
| 0f1ff5ffd2 | |||
| 9512fc34f0 | |||
| 75348922fc | |||
| 938eb2d0f0 | |||
| ede51fa589 | |||
| 7e0711ce12 | |||
| 822f40239f | |||
| 31149e6ba1 | |||
| ba233b6016 | |||
| 3d17ab6a4b | |||
| 492f1dd199 | |||
| 172399f792 | |||
| 22407c2911 | |||
| bdace0f9cb | |||
| 15bbba590b | |||
| a72264c685 | |||
| 2612cca708 | |||
| fc16d1c839 | |||
| f22bb282ab | |||
| d907b6b81a | |||
| 1903938035 | |||
| bb646c4f6a | |||
| 99e64a7bc1 | |||
| 7b960fa8a4 | |||
| 4c65ef3a2f | |||
| a4d84ffb1b | |||
| c495762a42 | |||
| 8d60a3ef6e | |||
| e24f8aa219 | |||
| de864fe828 | |||
| 8bc8671678 | |||
| c37d6b9296 | |||
| a4d1d2c354 | |||
| 0a59e21d97 | |||
| 911a3d0c04 | |||
| 163d4ff5fb | |||
| 2b84b5472b | |||
| c4ad3b8f05 | |||
| fe33df723b | |||
| 3a0e499199 | |||
| ce23662270 | |||
| c6e41ca3f3 | |||
| 9f0971f8a9 | |||
| 538616af54 | |||
| 6333042826 | |||
| b6d9ca2056 | |||
| 844d612808 | |||
| 9becf5457f | |||
| 3d07f1eeb9 | |||
| 0747e12273 | |||
| 5f4d56c1d8 | |||
| 390e58f603 | |||
| 6cf16d9c8f | |||
| 1368ab133e | |||
| ff1d92b576 | |||
| 1703a0a6f5 | |||
| 344eb92396 | |||
| 8a77287eaa | |||
| 9bfda6a254 | |||
| 147be7afd9 | |||
| 0a2ce7fa6d | |||
| 72f24c2c9d | |||
| f5b5d139ac | |||
| 2da6fdc2e8 | |||
| f7574924a8 | |||
| 5d07115706 | |||
| 9e994dfd55 | |||
| 59bc7cb53d | |||
| 655ff9bffb | |||
| a03cb1ef9f | |||
| 60f965ec52 | |||
| 8d26e48a5b | |||
| 94527ab594 | |||
| e312a28aad | |||
| e84a0c4438 | |||
| 6f1a0d987d | |||
| 48ceb9d1ce | |||
| e82e8b8bc3 | |||
| 3caa4c15ca | |||
| 741131f376 | |||
| ae6f161cd6 | |||
| b940c87d64 | |||
| fe6c685ab1 | |||
| c64c36022f | |||
| e52fe65985 | |||
| fea64d4d4f | |||
| 6ff02bc2a1 | |||
| 8b166f12f8 | |||
| ecdbe034fa | |||
| 3e46c8630d | |||
| 93e962524a | |||
| 5b6c1c032c | |||
| 135f1a6e7f | |||
| c61f89144e | |||
| 67fe368e65 | |||
| 522229459b | |||
| e3d8b71ea2 | |||
| 4f98fde362 | |||
| aa75e54419 | |||
| 5190a541a6 | |||
| 3a39fff006 | |||
| 0e302b83ab | |||
| 0d0637fe19 | |||
| 1f0c0090dc | |||
| 4f960330b1 | |||
| a273980aa0 | |||
| 13a55f00d8 | |||
| 4feec780d4 | |||
| 35c044c340 | |||
| ac5539a0fa | |||
| 9c569cbb62 | |||
| 72485cacd3 | |||
| 56d36d2c46 | |||
| 8fb54dd4e7 | |||
| 44d59ff8c2 | |||
| a8caf19f8c | |||
| 53b44fb9c6 | |||
| c0959e853e | |||
| 144df00782 | |||
| be4708cc84 | |||
| d5cddec03c | |||
| 7c26cab4e6 | |||
| f0bcf8c36f | |||
| ac2f0a172e | |||
| 898070bc87 | |||
| cc707660aa | |||
| 31624cf4e4 | |||
| e6a69170a4 | |||
| bc5e19514e | |||
| 5c76b8483e | |||
| a9526c216f | |||
| 903af16a6b | |||
| 0de79b6953 | |||
| fd2fafb52a | |||
| fadb5b4ff9 | |||
| 955583d0f0 | |||
| 3924c53d09 | |||
| c0025ee9c6 | |||
| 7dd0516b63 | |||
| d3cd3c9157 | |||
| 83680473e0 | |||
| 7f9a9f7a0a | |||
| e7ccb38502 | |||
| 1f4c19d396 | |||
| 64842f40d7 | |||
| 2ec18721fc | |||
| 2ef1ac452f | |||
| 6b3700aefe | |||
| e2e06df4e6 | |||
| 835d4f46f6 | |||
| d71ef635e2 | |||
| 6e3773a095 | |||
| 17a30be842 | |||
| d785d621ec | |||
| 904caca9de | |||
| 050d370396 | |||
| 29340ed00c | |||
| 2b062b3e5b | |||
| b405adb9e5 | |||
| 5c3c0ac39e | |||
| 1cc06ef349 | |||
| 2bef1603ab | |||
| 11a458a43d | |||
| 55775b6e7b | |||
| bb959544af | |||
| f7853c5531 | |||
| e6d2626fd7 | |||
| 08a2bc5c8d | |||
| 6d09e6fa7c | |||
| b1f4ae434a | |||
| 1647c368fb | |||
| 1fbf37e0ec | |||
| 1acdb0c519 | |||
| bc8efda08f | |||
| cecd0b2b0a | |||
| 62fa2ae5e4 | |||
| db2ce8070c | |||
| 70138ff54a | |||
| 30e93c33bb | |||
| ec4955f814 | |||
| e013517348 | |||
| e2302466cc |
@@ -15,8 +15,8 @@
|
||||
* @futurechimp @mmsinclair
|
||||
|
||||
# Rust rules:
|
||||
*.rs @durch @futurechimp @jstuczyn @neacsu
|
||||
Cargo.* @durch @futurechimp @jstuczyn @neacsu
|
||||
*.rs @durch @futurechimp @jstuczyn @neacsu @octol
|
||||
Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol
|
||||
|
||||
# JS rules:
|
||||
*.js @mmsinclair @fmtabbara @Aid19801
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
name: CI for ts-packages
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'ts-packages/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-runner-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16'
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Build
|
||||
run: yarn && yarn build && yarn build:ci
|
||||
- name: Deploy branch to CI www (storybook)
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "ts-packages/dist/storybook/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Deploy branch to CI www (example)
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "ts-packages/dist/example/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}-example
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Keybase - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: ts-packages
|
||||
NYM_PROJECT_NAME: "ts-packages"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
||||
KEYBASE_NYM_CHANNEL: "ci-ts-packages"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
@@ -9,28 +9,14 @@ on:
|
||||
- 'explorer/**'
|
||||
|
||||
jobs:
|
||||
matrix_prep:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
# creates the matrix strategy from build_matrix_includes.json
|
||||
- uses: actions/checkout@v2
|
||||
- id: set-matrix
|
||||
uses: JoshuaTheMiller/conditional-build-matrix@main
|
||||
with:
|
||||
inputFile: '.github/workflows/build_matrix_includes.json'
|
||||
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
|
||||
build:
|
||||
needs: matrix_prep
|
||||
strategy:
|
||||
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.os == 'windows-latest' }}
|
||||
runs-on: [ self-hosted, custom-linux-exoscale ]
|
||||
# Enable sccache via environment variable
|
||||
env:
|
||||
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
||||
steps:
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
@@ -39,7 +25,7 @@ jobs:
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
toolchain: stable
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
@@ -47,13 +33,13 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --all
|
||||
args: --workspace
|
||||
|
||||
- name: Run all tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
args: --workspace --all-features
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
@@ -63,40 +49,30 @@ jobs:
|
||||
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
name: Clippy checks
|
||||
# if: matrix.os == 'ubuntu-latest' && matrix.rust == 'stable'
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: -- -D warnings
|
||||
|
||||
# COCONUT stuff
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
with:
|
||||
command: clean
|
||||
args: --workspace -- -D warnings
|
||||
|
||||
- name: Build all binaries with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --all --features=coconut
|
||||
args: --workspace --features=coconut
|
||||
|
||||
- name: Run all tests with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all --features=coconut
|
||||
args: --workspace --features=coconut
|
||||
|
||||
- name: Run clippy with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: --features=coconut -- -D warnings
|
||||
args: --features=coconut -- -D warnings
|
||||
|
||||
@@ -10,41 +10,10 @@
|
||||
"rust":"stable",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"stable",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"ubuntu-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"ubuntu-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"pull_request"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
RUSTFLAGS: '-C link-arg=-s'
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path contracts/Cargo.toml --all --target wasm32-unknown-unknown
|
||||
args: --manifest-path contracts/Cargo.toml --workspace --target wasm32-unknown-unknown
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
@@ -61,4 +61,4 @@ jobs:
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: --manifest-path contracts/Cargo.toml --all -- -D warnings
|
||||
args: --manifest-path contracts/Cargo.toml --workspace -- -D warnings
|
||||
|
||||
@@ -16,8 +16,9 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14'
|
||||
- run: npm install
|
||||
node-version: '16'
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Run ESLint
|
||||
# GitHub should automatically annotate the PR
|
||||
run: npm run lint
|
||||
run: yarn && yarn lint
|
||||
@@ -19,14 +19,17 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14'
|
||||
- run: npm install
|
||||
node-version: '16'
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
continue-on-error: true
|
||||
- name: Build shared packages
|
||||
run: cd .. && yarn && yarn build
|
||||
- name: Set environment from the example
|
||||
run: cp .env.prod .env
|
||||
- run: npm run test
|
||||
continue-on-error: true
|
||||
- run: npm run build
|
||||
# - run: yarn test
|
||||
# continue-on-error: true
|
||||
- run: yarn && yarn build
|
||||
continue-on-error: true
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
@@ -41,9 +44,10 @@ jobs:
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Keybase - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files/messages
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: network-explorer
|
||||
NYM_PROJECT_NAME: "Network Explorer"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "network-explorer-${{ env.GITHUB_REF_SLUG }}"
|
||||
@@ -56,4 +60,4 @@ jobs:
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/messages/entry_point_notifications.sh
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
name: Nightly builds
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '14 4 * * *'
|
||||
jobs:
|
||||
matrix_prep:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
# creates the matrix strategy from nightly_build_matrix_includes.json
|
||||
- uses: actions/checkout@v2
|
||||
- id: set-matrix
|
||||
uses: JoshuaTheMiller/conditional-build-matrix@main
|
||||
with:
|
||||
inputFile: '.github/workflows/nightly_build_matrix_includes.json'
|
||||
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
|
||||
build:
|
||||
needs: matrix_prep
|
||||
strategy:
|
||||
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
|
||||
steps:
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Build all binaries
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace
|
||||
|
||||
- name: Run all tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
name: Clippy checks
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: --workspace --all-targets -- -D warnings
|
||||
|
||||
|
||||
# COCONUT stuff
|
||||
- name: Build all binaries with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --features=coconut
|
||||
|
||||
- name: Run all tests with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace --features=coconut
|
||||
|
||||
- name: Run clippy with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: --workspace --all-targets --features=coconut -- -D warnings
|
||||
notification:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Collect jobs status
|
||||
uses: technote-space/workflow-conclusion-action@v2
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
- name: Keybase - Node Install
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: nightly
|
||||
NYM_PROJECT_NAME: "Nym nightly build"
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
||||
KEYBASE_NYM_CHANNEL: "ci-nightly"
|
||||
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"os":"ubuntu-latest",
|
||||
"rust":"stable",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"rust":"stable",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"stable",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"ubuntu-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"ubuntu-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"schedule"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,77 @@
|
||||
name: Publish Nym Wallet (MacOS)
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-wallet
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [macos-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Check the release tag starts with `nym-wallet-`
|
||||
if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-wallet-...')
|
||||
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16.x
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install the Apple developer certificate for code signing
|
||||
env:
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
run: |
|
||||
# create variables
|
||||
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
|
||||
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
||||
|
||||
# import certificate and provisioning profile from secrets
|
||||
echo -n "$APPLE_CERTIFICATE" | base64 --decode --output $CERTIFICATE_PATH
|
||||
|
||||
# create temporary keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
|
||||
# import certificate to keychain
|
||||
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
- name: Install app dependencies and build it
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_IDENTITY_ID }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
run: yarn && yarn build
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: nym-wallet/target/release/bundle/dmg/*.dmg
|
||||
|
||||
- name: Clean up keychain
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
||||
@@ -0,0 +1,46 @@
|
||||
name: Publish Nym Wallet (Ubuntu)
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-wallet
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Tauri dependencies
|
||||
run: >
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install -y webkit2gtk-4.0
|
||||
- name: Check the release tag starts with `nym-wallet-`
|
||||
if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-wallet-...')
|
||||
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16.x
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install app dependencies and build it
|
||||
run: yarn && yarn build
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: nym-wallet/target/release/bundle/appimage/*.AppImage
|
||||
@@ -1,12 +0,0 @@
|
||||
name: Publish Nym Wallet
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- nym-wallet-*
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run a one-line script
|
||||
run: echo Hello, world!
|
||||
@@ -1,29 +0,0 @@
|
||||
name: Generate TS types
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "explorer/**"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "explorer/**"
|
||||
|
||||
jobs:
|
||||
nym-wallet-types:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
steps:
|
||||
- name: Prepare
|
||||
run: sudo apt-get update && sudo apt-get install -y libpango1.0-dev libatk1.0-dev libgdk-pixbuf2.0-dev libsoup2.4-dev librust-gdk-dev libwebkit2gtk-4.0-dev
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Generate TS
|
||||
run: cd nym-wallet/src-tauri && cargo test
|
||||
- uses: EndBug/add-and-commit@v7.2.1 # https://github.com/marketplace/actions/add-commit
|
||||
with:
|
||||
add: '["nym-wallet"]'
|
||||
message: "[ci skip] Generate TS types"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,35 @@
|
||||
KEYBASE_NYM_CHANNEL=
|
||||
KEYBASE_NYMBOT_USERNAME=
|
||||
KEYBASE_NYMBOT_PAPERKEY=
|
||||
|
||||
NYM_NOTIFICATION_KIND=nightly
|
||||
NYM_PROJECT_NAME=Nightly Build
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Custom GitHub Actions mock env vars
|
||||
IS_SUCCESS=true
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# GitHub Actions context mock env vars
|
||||
GITHUB_SHA=abcdef
|
||||
GITHUB_RUN_ID=123456
|
||||
GITHUB_REPOSITORY=nymtech/nym
|
||||
GITHUB_SERVER_URL=https://github.com
|
||||
GIT_BRANCH_NAME=feature/testing-support-files
|
||||
GIT_BRANCH=feature/testing-support-files
|
||||
GIT_COMMIT_MESSAGE=This is the commit message
|
||||
GITHUB_ACTOR=octocat
|
||||
|
||||
# add a Personal Access Token (PAT) generated from GitHub here for use in testing
|
||||
GITHUB_TOKEN=
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Network Explorer
|
||||
NYM_CI_WWW_LOCATION=some-branch
|
||||
NYM_CI_WWW_BASE=example.com
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Nightly builds
|
||||
WORKFLOW_CONCLUSION=success
|
||||
|
||||
SHOW_DEBUG=true
|
||||
@@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
.idea
|
||||
|
||||
# don't commit the lock file to avoid cross-platform issues
|
||||
package-lock.json
|
||||
@@ -0,0 +1 @@
|
||||
16
|
||||
@@ -0,0 +1,58 @@
|
||||
# GitHub Actions Support Files
|
||||
|
||||
This is a collection of scripts and files to support GitHub Actions.
|
||||
|
||||
## Sending Notifications
|
||||
|
||||
These scripts send CI notifications to Keybase by creating messages from templates and env vars passed from GitHub Actions.
|
||||
|
||||
### Adding notifications to a GitHub Action
|
||||
|
||||
```
|
||||
jobs:
|
||||
build:
|
||||
...
|
||||
- name: Notifications - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files/notifications
|
||||
- name: Notifications - Send
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: "my-component"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
||||
KEYBASE_NYM_CHANNEL: "ci-network-explorer"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
```
|
||||
|
||||
Notifications are run by adding the snippet above to a GitHub Action, and:
|
||||
|
||||
1. Installing node packages needed at run time
|
||||
2. Set the env vars as required:
|
||||
- `NYM_NOTIFICATION_KIND` matches the directory in `.github/workflows/support-files/${NYM_NOTIFICATION_KIND}` to provide the templates and extra scripting in `index.js`
|
||||
- Keybase credentials, channel and other env vars for the status of the build and repo
|
||||
3. Replacing the default entry point shell script on the `keybaseio/client:stable-node` docker image to run `.github/workflows/support-files/notifications/entry_point.sh`
|
||||
|
||||
### Running locally
|
||||
|
||||
You will need:
|
||||
- Node 16 LTS
|
||||
- npm
|
||||
|
||||
Copy `.github/workflows/support-files/.env.example` to `.github/workflows/support-files/.env` and valid Keybase credentials.
|
||||
|
||||
Then run `npm install` to get dependencies.
|
||||
|
||||
Start development mode for the notification type you want either by passing the value as an env var called `NYM_NOTIFICATION_KIND` or set the `.env` file values correctly.
|
||||
|
||||
```bash
|
||||
cd .github/workflows/support-files
|
||||
npm install
|
||||
cp .env.example .env
|
||||
vi .env
|
||||
npm run dev
|
||||
```
|
||||
@@ -0,0 +1 @@
|
||||
require('./notifications/send_message');
|
||||
@@ -1,2 +0,0 @@
|
||||
node_modules
|
||||
.idea
|
||||
@@ -1,69 +0,0 @@
|
||||
const Bot = require('keybase-bot');
|
||||
const Handlebars = require('handlebars');
|
||||
const fs = require('fs');
|
||||
|
||||
async function main() {
|
||||
const data = { env: process.env };
|
||||
// const data = { ...PASTE TEST DATA HERE ... }; // -- DEV: uncomment to set test data
|
||||
|
||||
// validation of environment
|
||||
if(!(process.env.NYM_PROJECT_NAME || data.env.NYM_PROJECT_NAME)) {
|
||||
throw new Error('Please set env var NYM_PROJECT_NAME with the project name for displaying in notification messages');
|
||||
}
|
||||
const keybaseChannel = process.env.KEYBASE_NYM_CHANNEL || data.env.KEYBASE_NYM_CHANNEL;
|
||||
if(!keybaseChannel) {
|
||||
throw new Error('Please set env var KEYBASE_NYM_CHANNEL with the channel name for the notification message');
|
||||
}
|
||||
|
||||
// extract the git branch name
|
||||
const GIT_BRANCH_NAME = (process.env.GITHUB_REF || data.env.GITHUB_REF).split('/').slice(2).join('/');
|
||||
|
||||
data.env.GIT_BRANCH_NAME = GIT_BRANCH_NAME;
|
||||
const source = fs
|
||||
.readFileSync(process.env.IS_SUCCESS === 'true' ? 'success' : 'failure')
|
||||
.toString();
|
||||
const template = Handlebars.compile(source);
|
||||
const result = template(data);
|
||||
|
||||
// -- DEV: uncomment to show what is available in the handlebars template / show the result
|
||||
// console.dir({ data }, { depth: null });
|
||||
// console.log(result);
|
||||
|
||||
const bot = new Bot();
|
||||
try {
|
||||
const username = process.env.KEYBASE_NYMBOT_USERNAME;
|
||||
const paperkey = process.env.KEYBASE_NYMBOT_PAPERKEY;
|
||||
|
||||
if(!username) {
|
||||
throw new Error('Username is not defined. Please set env var KEYBASE_NYMBOT_USERNAME');
|
||||
}
|
||||
if(!paperkey) {
|
||||
throw new Error('Paperkey is not defined. Please set env var KEYBASE_NYMBOT_PAPERKEY');
|
||||
}
|
||||
|
||||
console.log(`Initialising keybase with user "${username}" and key: "${'*'.repeat(paperkey.length)}"...`);
|
||||
await bot.init(username, paperkey, { verbose: false });
|
||||
|
||||
const channel = {
|
||||
name: 'nymtech_bot',
|
||||
membersType: 'team',
|
||||
topicName: keybaseChannel,
|
||||
topic_type: 'CHAT',
|
||||
};
|
||||
const message = {
|
||||
body: result,
|
||||
};
|
||||
|
||||
console.log(`Sending to ${channel.name}#${channel.topicName}...`);
|
||||
await bot.chat.send(channel, message);
|
||||
|
||||
console.log('Message sent!');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
process.exitCode = -1;
|
||||
} finally {
|
||||
await bot.deinit();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -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,
|
||||
};
|
||||
@@ -5,7 +5,7 @@
|
||||
> `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:
|
||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||
```
|
||||
{{ env.GIT_COMMIT_MESSAGE }}
|
||||
```
|
||||
@@ -0,0 +1,162 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Octokit, App } = require('octokit');
|
||||
|
||||
async function addToContextAndValidate(context) {
|
||||
if (!context.env.WORKFLOW_CONCLUSION) {
|
||||
throw new Error('Please ensure the env var WORKFLOW_CONCLUSION is set');
|
||||
}
|
||||
if (!context.env.GITHUB_TOKEN) {
|
||||
throw new Error('Please ensure the env var GITHUB_TOKEN is set');
|
||||
}
|
||||
if (!context.env.GITHUB_RUN_ID) {
|
||||
throw new Error('Please ensure the env var GITHUB_RUN_ID is set');
|
||||
}
|
||||
if (!context.env.GITHUB_REPOSITORY) {
|
||||
throw new Error('Please ensure the env var GITHUB_REPOSITORY is set');
|
||||
}
|
||||
}
|
||||
|
||||
async function getMessageBody(context) {
|
||||
const source = fs
|
||||
.readFileSync(
|
||||
context.env.WORKFLOW_CONCLUSION === 'success'
|
||||
? path.resolve(__dirname, 'templates', 'success')
|
||||
: path.resolve(__dirname, 'templates', 'failure'),
|
||||
)
|
||||
.toString();
|
||||
const template = Handlebars.compile(source);
|
||||
|
||||
// get job details from GitHub API
|
||||
const octokit = new Octokit({ auth: context.env.GITHUB_TOKEN });
|
||||
const [owner, repo] = context.env.GITHUB_REPOSITORY.split('/');
|
||||
const {
|
||||
data: { jobs },
|
||||
} = await octokit.rest.actions.listJobsForWorkflowRun({
|
||||
run_id: context.env.GITHUB_RUN_ID,
|
||||
owner,
|
||||
repo,
|
||||
});
|
||||
|
||||
// uncomment this to see what is available for each job
|
||||
if(process.env.SHOW_DEBUG) {
|
||||
console.dir(jobs, { depth: null });
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
a sample of the response is:
|
||||
|
||||
{
|
||||
total_count: 10,
|
||||
jobs: [
|
||||
{
|
||||
id: 5182940024,
|
||||
run_id: 1840752095,
|
||||
run_url: 'https://api.github.com/repos/nymtech/nym/actions/runs/1840752095',
|
||||
run_attempt: 1,
|
||||
node_id: 'CR_kwDODdjOis8AAAABNO1jeA',
|
||||
head_sha: 'aa00eb70d57751bfa556bd3602df87c7473367fc',
|
||||
url: 'https://api.github.com/repos/nymtech/nym/actions/jobs/5182940024',
|
||||
html_url: 'https://github.com/nymtech/nym/runs/5182940024?check_suite_focus=true',
|
||||
status: 'completed',
|
||||
conclusion: 'success',
|
||||
started_at: '2022-02-14T11:28:34Z',
|
||||
completed_at: '2022-02-14T11:28:38Z',
|
||||
name: 'matrix_prep',
|
||||
steps: [
|
||||
{
|
||||
name: 'Set up job',
|
||||
status: 'completed',
|
||||
conclusion: 'success',
|
||||
number: 1,
|
||||
started_at: '2022-02-14T13:28:34.000+02:00',
|
||||
completed_at: '2022-02-14T13:28:36.000+02:00'
|
||||
},
|
||||
{
|
||||
name: 'Run actions/checkout@v2',
|
||||
status: 'completed',
|
||||
conclusion: 'success',
|
||||
number: 2,
|
||||
started_at: '2022-02-14T13:28:36.000+02:00',
|
||||
completed_at: '2022-02-14T13:28:37.000+02:00'
|
||||
},
|
||||
...
|
||||
],
|
||||
check_run_url: 'https://api.github.com/repos/nymtech/nym/check-runs/5182940024',
|
||||
labels: [ 'ubuntu-latest' ],
|
||||
runner_id: 1,
|
||||
runner_name: 'Hosted Agent',
|
||||
runner_group_id: 2,
|
||||
runner_group_name: 'GitHub Actions'
|
||||
},
|
||||
{
|
||||
id: 5182943473,
|
||||
run_id: 1840752095,
|
||||
run_url: 'https://api.github.com/repos/nymtech/nym/actions/runs/1840752095',
|
||||
run_attempt: 1,
|
||||
node_id: 'CR_kwDODdjOis8AAAABNO1w8Q',
|
||||
head_sha: 'aa00eb70d57751bfa556bd3602df87c7473367fc',
|
||||
url: 'https://api.github.com/repos/nymtech/nym/actions/jobs/5182943473',
|
||||
html_url: 'https://github.com/nymtech/nym/runs/5182943473?check_suite_focus=true',
|
||||
status: 'completed',
|
||||
conclusion: 'failure',
|
||||
started_at: '2022-02-14T11:29:04Z',
|
||||
completed_at: '2022-02-14T11:55:45Z',
|
||||
name: 'build (macos-latest, stable, schedule)',
|
||||
steps: [
|
||||
{
|
||||
name: 'Set up job',
|
||||
status: 'completed',
|
||||
conclusion: 'success',
|
||||
number: 1,
|
||||
started_at: '2022-02-14T13:29:04.000+02:00',
|
||||
completed_at: '2022-02-14T13:29:26.000+02:00'
|
||||
},
|
||||
{
|
||||
name: 'Install Dependencies (Linux)',
|
||||
status: 'completed',
|
||||
conclusion: 'skipped',
|
||||
number: 2,
|
||||
started_at: '2022-02-14T13:29:26.000+02:00',
|
||||
completed_at: '2022-02-14T13:29:26.000+02:00'
|
||||
},
|
||||
{
|
||||
name: 'Keybase - Send Notification',
|
||||
status: 'completed',
|
||||
conclusion: 'failure',
|
||||
number: 15,
|
||||
started_at: '2022-02-14T13:55:44.000+02:00',
|
||||
completed_at: '2022-02-14T13:55:44.000+02:00'
|
||||
},
|
||||
],
|
||||
check_run_url: 'https://api.github.com/repos/nymtech/nym/check-runs/5182943473',
|
||||
labels: [ 'macos-latest' ],
|
||||
runner_id: 4,
|
||||
runner_name: 'GitHub Actions 4',
|
||||
runner_group_id: 2,
|
||||
runner_group_name: 'GitHub Actions'
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
||||
const jobResults = jobs
|
||||
.map((job) => {
|
||||
const icon = job.conclusion === 'success' ? '🟩' : '🟥';
|
||||
|
||||
// each job is converted into formatted markdown text
|
||||
return `${icon} ${job.conclusion}: ${job.name} - ${job.html_url}`;
|
||||
})
|
||||
// and join with newlines for display in the template
|
||||
.join('\n');
|
||||
|
||||
return template({ ...context, jobResults });
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addToContextAndValidate,
|
||||
getMessageBody,
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
> 🔴 **FAILURE** :cry:
|
||||
> `when` {{ timestamp }}
|
||||
> `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 }}
|
||||
|
||||
{{ jobResults }}
|
||||
@@ -0,0 +1,9 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
> ✅ **SUCCESS**
|
||||
> `when` {{ timestamp }}
|
||||
> `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 }}
|
||||
|
||||
{{ jobResults }}
|
||||
@@ -0,0 +1,153 @@
|
||||
require('dotenv').config();
|
||||
|
||||
const Bot = require('keybase-bot');
|
||||
|
||||
let context = {
|
||||
kinds: ['ts-packages', 'network-explorer', 'nightly'],
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate that all required env and context vars are available
|
||||
*/
|
||||
function validateContext() {
|
||||
if (!context.env.NYM_NOTIFICATION_KIND) {
|
||||
throw new Error(
|
||||
'Please set env var NYM_NOTIFICATION_KIND with the project kind that matches a directory in ".github/workflows/support-files"',
|
||||
);
|
||||
}
|
||||
if (!context.kinds.includes(context.env.NYM_NOTIFICATION_KIND)) {
|
||||
throw new Error(`Env var NYM_NOTIFICATION_KIND is not in ${context.kinds}`);
|
||||
}
|
||||
if (!context.env.NYM_PROJECT_NAME) {
|
||||
throw new Error(
|
||||
'Please set env var NYM_PROJECT_NAME with the project name for displaying in notification messages',
|
||||
);
|
||||
}
|
||||
if (!context.env.KEYBASE_NYM_CHANNEL) {
|
||||
throw new Error(
|
||||
'Please set env var KEYBASE_NYM_CHANNEL with the channel name for the notification message',
|
||||
);
|
||||
}
|
||||
if (!context.env.KEYBASE_NYMBOT_USERNAME) {
|
||||
throw new Error(
|
||||
'Username is not defined. Please set env var KEYBASE_NYMBOT_USERNAME',
|
||||
);
|
||||
}
|
||||
if (!context.env.KEYBASE_NYMBOT_PAPERKEY) {
|
||||
throw new Error(
|
||||
'Paperkey is not defined. Please set env var KEYBASE_NYMBOT_PAPERKEY',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a context that will be available in the templates for rendering notifications
|
||||
*/
|
||||
function createTemplateContext() {
|
||||
const options = { dateStyle: 'full', timeStyle: 'long' };
|
||||
context.timestamp = new Date().toLocaleString(undefined, options);
|
||||
|
||||
// add environment to template context and validate
|
||||
context.env = process.env;
|
||||
try {
|
||||
validateContext();
|
||||
} catch (e) {
|
||||
if(process.env.SHOW_DEBUG) {
|
||||
// recursively print the context for easy debugging and rethrow the error
|
||||
console.dir({ context }, { depth: null });
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
context.kind = context.env.NYM_NOTIFICATION_KIND;
|
||||
|
||||
context.keybase = {
|
||||
channel: context.env.KEYBASE_NYM_CHANNEL,
|
||||
username: context.env.KEYBASE_NYMBOT_USERNAME,
|
||||
paperkey: context.env.KEYBASE_NYMBOT_PAPERKEY,
|
||||
};
|
||||
|
||||
if (!context.env.GIT_BRANCH_NAME) {
|
||||
context.env.GIT_BRANCH_NAME = context.env.GITHUB_REF.split('/')
|
||||
.slice(2)
|
||||
.join('/');
|
||||
}
|
||||
|
||||
context.status = process.env.IS_SUCCESS === 'true' ? 'success' : 'failure';
|
||||
}
|
||||
|
||||
async function sendKeybaseMessage(messageBody) {
|
||||
const bot = new Bot();
|
||||
try {
|
||||
console.log(
|
||||
`Initialising keybase with user "${
|
||||
context.keybase.username
|
||||
}" and key: "${'*'.repeat(context.keybase.paperkey.length)}"...`,
|
||||
);
|
||||
await bot.init(context.keybase.username, context.keybase.paperkey, {
|
||||
verbose: false,
|
||||
});
|
||||
|
||||
const channel = {
|
||||
name: 'nymtech_bot',
|
||||
membersType: 'team',
|
||||
topicName: context.keybase.channel,
|
||||
topic_type: 'CHAT',
|
||||
};
|
||||
const message = {
|
||||
body: messageBody,
|
||||
};
|
||||
|
||||
console.log(`Sending to ${channel.name}#${channel.topicName}...`);
|
||||
await bot.chat.send(channel, message);
|
||||
|
||||
console.log('Message sent!');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
process.exitCode = -1;
|
||||
} finally {
|
||||
await bot.deinit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the `kind` set in the context to process the context and generate a notification message
|
||||
* @returns {Promise<string>} A string notification message body
|
||||
*/
|
||||
async function processKindScript() {
|
||||
const script = require(`../${context.kind}`);
|
||||
if (!script.addToContextAndValidate) {
|
||||
throw new Error(
|
||||
`"./${context.kind}/index.js" does not export a method called "async addToContextAndValidate(context)"`,
|
||||
);
|
||||
}
|
||||
if (!script.getMessageBody) {
|
||||
throw new Error(
|
||||
`"./${context.kind}/index.js" does not export a method called "async getMessageBody(context)"`,
|
||||
);
|
||||
}
|
||||
|
||||
// call the script to modify and validate the context
|
||||
await script.addToContextAndValidate(context);
|
||||
|
||||
// let the script create a message body and return the result as a string for sending
|
||||
return await script.getMessageBody(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* The main function, as async so that await syntax is available
|
||||
*/
|
||||
async function main() {
|
||||
createTemplateContext();
|
||||
console.log(`Sending notification for kind "${context.kind}"...`);
|
||||
const messageBody = await processKindScript();
|
||||
if(process.env.SHOW_DEBUG) {
|
||||
console.log('-----------------------------------------');
|
||||
console.log(messageBody);
|
||||
console.log('-----------------------------------------');
|
||||
}
|
||||
await sendKeybaseMessage(messageBody);
|
||||
}
|
||||
|
||||
// call main function and let NodeJS handle the promise
|
||||
main();
|
||||
@@ -4,11 +4,14 @@
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"format": "prettier --write send_message.js"
|
||||
"dev": "node dev.js",
|
||||
"format": "prettier --write **/*.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"keybase-bot": "^3.6.1"
|
||||
"keybase-bot": "^3.6.1",
|
||||
"octokit": "^1.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "2.3.2"
|
||||
@@ -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,16 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
> ✅ **SUCCESS**
|
||||
|
||||
> ➡️➡️➡️➡️➡️ **View output:**
|
||||
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}
|
||||
> `example`: https://{{ env.NYM_CI_WWW_LOCATION }}-example.{{ env.NYM_CI_WWW_BASE }}
|
||||
|
||||
> `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 }}
|
||||
```
|
||||
@@ -19,30 +19,27 @@ jobs:
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
# token credentials (non-coconut) don't work for wasm right now
|
||||
# - uses: actions-rs/cargo@v1
|
||||
# with:
|
||||
# command: build
|
||||
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --features=coconut
|
||||
|
||||
# for some reason this does not seem to work correctly, leave it for later, building is good enough for now
|
||||
# - uses: actions-rs/cargo@v1
|
||||
# with:
|
||||
# command: test
|
||||
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --manifest-path clients/webassembly/Cargo.toml
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --manifest-path clients/webassembly/Cargo.toml -- --check
|
||||
|
||||
# for some reason this does not seem to work correctly, leave it for later, building is good enough for now
|
||||
# - uses: actions-rs/cargo@v1
|
||||
# with:
|
||||
# command: clippy
|
||||
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
|
||||
|
||||
@@ -35,4 +35,6 @@ contracts/mixnet/Justfile
|
||||
contracts/mixnet/Makefile
|
||||
validator-config
|
||||
*.patch
|
||||
validator-api-config.toml
|
||||
validator-api-config.toml
|
||||
dist
|
||||
storybook-static
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"mainnet":[{
|
||||
"nymd_url":"https://rpc.nyx.nodes.guru/",
|
||||
"api_url":"https://api.nyx.nodes.guru/"
|
||||
}]
|
||||
}
|
||||
@@ -11,13 +11,13 @@ panic = "abort"
|
||||
|
||||
[workspace]
|
||||
|
||||
resolver = "2"
|
||||
members = [
|
||||
"clients/client-core",
|
||||
"clients/native",
|
||||
"clients/native/websocket-requests",
|
||||
"clients/socks5",
|
||||
"clients/tauri-client/src-tauri",
|
||||
"clients/webassembly",
|
||||
# "clients/tauri-client/src-tauri",
|
||||
"common/client-libs/gateway-client",
|
||||
"common/client-libs/mixnet-client",
|
||||
"common/client-libs/validator-client",
|
||||
@@ -26,11 +26,16 @@ members = [
|
||||
"common/credentials",
|
||||
"common/crypto",
|
||||
"common/bandwidth-claim-contract",
|
||||
"common/mixnet-contract",
|
||||
"common/cosmwasm-smart-contracts/contracts-common",
|
||||
"common/cosmwasm-smart-contracts/mixnet-contract",
|
||||
"common/cosmwasm-smart-contracts/vesting-contract",
|
||||
"common/mixnode-common",
|
||||
"common/network-defaults",
|
||||
"common/nonexhaustive-delayqueue",
|
||||
"common/nymcoconut",
|
||||
"common/nym_offline_compact_ecash",
|
||||
"common/nym_offline_divisible_ecash",
|
||||
"common/nym_online_divisible_ecash",
|
||||
"common/nymsphinx",
|
||||
"common/nymsphinx/acknowledgements",
|
||||
"common/nymsphinx/addressing",
|
||||
@@ -52,12 +57,12 @@ members = [
|
||||
"mixnode",
|
||||
"service-providers/network-requester",
|
||||
"validator-api",
|
||||
"validator-api/validator-api-requests",
|
||||
]
|
||||
|
||||
default-members = [
|
||||
"clients/native",
|
||||
"clients/socks5",
|
||||
# "clients/webassembly",
|
||||
"gateway",
|
||||
"service-providers/network-requester",
|
||||
"mixnode",
|
||||
@@ -65,4 +70,4 @@ default-members = [
|
||||
"explorer-api",
|
||||
]
|
||||
|
||||
exclude = ["explorer", "contracts", "tokenomics-py"]
|
||||
exclude = ["explorer", "contracts", "tokenomics-py", "clients/webassembly"]
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
all: clippy-all test fmt
|
||||
happy: clippy-happy test fmt
|
||||
test: build clippy-all cargo-test wasm fmt
|
||||
no-clippy: build cargo-test wasm fmt
|
||||
happy: fmt clippy-happy test
|
||||
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet
|
||||
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet
|
||||
test: test-main test-contracts test-wallet
|
||||
cargo-test: test-main test-contracts test-wallet
|
||||
build: build-contracts build-wallet build-main
|
||||
fmt: fmt-main fmt-contracts fmt-wallet
|
||||
|
||||
clippy-happy-main:
|
||||
@@ -11,20 +13,20 @@ clippy-happy-main:
|
||||
clippy-happy-contracts:
|
||||
cargo clippy --manifest-path contracts/Cargo.toml --target wasm32-unknown-unknown
|
||||
|
||||
clippy-happy-wallet:
|
||||
clippy-happy-wallet:
|
||||
cargo clippy --manifest-path nym-wallet/Cargo.toml
|
||||
|
||||
clippy-all-main:
|
||||
cargo clippy --all-features -- -D warnings
|
||||
cargo clippy --workspace --all-features -- -D warnings
|
||||
|
||||
clippy-all-contracts:
|
||||
cargo clippy --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
|
||||
cargo clippy --workspace --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
|
||||
|
||||
clippy-all-wallet:
|
||||
cargo clippy --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
|
||||
clippy-all-wallet:
|
||||
cargo clippy --workspace --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
|
||||
|
||||
test-main:
|
||||
cargo test --all-features
|
||||
cargo test --all-features --workspace
|
||||
|
||||
test-contracts:
|
||||
cargo test --manifest-path contracts/Cargo.toml --all-features
|
||||
@@ -32,6 +34,15 @@ test-contracts:
|
||||
test-wallet:
|
||||
cargo test --manifest-path nym-wallet/Cargo.toml --all-features
|
||||
|
||||
build-main:
|
||||
cargo build --workspace
|
||||
|
||||
build-contracts:
|
||||
cargo build --manifest-path contracts/Cargo.toml --workspace
|
||||
|
||||
build-wallet:
|
||||
cargo build --manifest-path nym-wallet/Cargo.toml --workspace
|
||||
|
||||
fmt-main:
|
||||
cargo fmt --all
|
||||
|
||||
|
||||
@@ -21,12 +21,15 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
|
||||
### Building
|
||||
|
||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/0.11.0/overview/index/).
|
||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/stable/run-nym-nodes/build-nym).
|
||||
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/stable/nym-apps/wallet#for-developers).
|
||||
|
||||
### Developing
|
||||
|
||||
There's a `.env.sample-dev` file provided which you can rename to `.env` if you want convenient logging, backtrace, or other environment variables pre-set. The `.env` file is ignored so you don't need to worry about checking it in.
|
||||
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# Shared assets
|
||||
|
||||
This directory contains asset files shared by many projects in this repo.
|
||||
|
||||
You will find:
|
||||
|
||||
- favicons
|
||||
- logos
|
||||
- shared fonts
|
||||
- shared icon SVGs
|
||||
|
||||
See [ts-packages/react-webpack-with-theme-example](../ts-packages/react-webpack-with-theme-example) for examples of usage.
|
||||
|
After Width: | Height: | Size: 545 KiB |
@@ -0,0 +1,10 @@
|
||||
<svg width="64" height="64" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M40 78.5C61.263 78.5 78.5 61.263 78.5 40C78.5 18.737 61.263 1.5 40 1.5C18.737 1.5 1.5 18.737 1.5 40C1.5 61.263 18.737 78.5 40 78.5Z" fill="#070B15" stroke="url(#paint0_linear_0_1)" stroke-width="3"/>
|
||||
<path d="M31.4894 27.56L41.8623 56H48.5106H56V24H48.5106V52.4L38.1777 24H31.4894H24V56H31.4894V27.56Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_0_1" x1="0.839161" y1="80" x2="80" y2="80" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.09375" stop-color="#FB6E4E"/>
|
||||
<stop offset="1" stop-color="#F51473"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 672 B |
@@ -0,0 +1,6 @@
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('./OpenSans-VariableFont_wdth,wght.ttf') format('truetype-variations'),
|
||||
url('./OpenSans-Italic-VariableFont_wdth,wght.ttf') format('truetype-variations');
|
||||
font-weight: 100 1000;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<svg width="64" height="64" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M40 78.5C61.263 78.5 78.5 61.263 78.5 40C78.5 18.737 61.263 1.5 40 1.5C18.737 1.5 1.5 18.737 1.5 40C1.5 61.263 18.737 78.5 40 78.5Z" fill="#070B15" stroke="url(#paint0_linear_0_1)" stroke-width="3"/>
|
||||
<path d="M31.4894 27.56L41.8623 56H48.5106H56V24H48.5106V52.4L38.1777 24H31.4894H24V56H31.4894V27.56Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_0_1" x1="0.839161" y1="80" x2="80" y2="80" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.09375" stop-color="#FB6E4E"/>
|
||||
<stop offset="1" stop-color="#F51473"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 714 B |
@@ -0,0 +1,13 @@
|
||||
<svg width="300" height="300" viewBox="0 0 296 296" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M148 296C229.738 296 296 229.738 296 148C296 66.2619 229.738 0 148 0C66.2619 0 0 66.2619 0 148C0 229.738 66.2619 296 148 296Z" fill="url(#paint0_linear_113_1244)"/>
|
||||
<path d="M148 285.875C224.147 285.875 285.875 224.146 285.875 148C285.875 71.8536 224.147 10.1248 148 10.1248C71.8538 10.1248 10.125 71.8536 10.125 148C10.125 224.146 71.8538 285.875 148 285.875Z" fill="#121725"/>
|
||||
<path d="M88.8829 120.143H88.7169V120.281V168.637L68.3289 120.226L68.3012 120.143H68.1905H56.6272H43.653H43.5146V120.281V175.719V175.857H43.653H56.6272H56.7655V175.719V127.28L77.2365 175.774L77.2642 175.857H77.3748H88.8829H101.829H101.968V175.719V120.281V120.143H101.829H88.8829Z" fill="white"/>
|
||||
<path d="M252.347 120.143H227.616H227.477L227.45 120.253L214.78 168.858L202.082 120.253L202.054 120.143H201.944H177.157H176.991V120.281V175.719V175.857H177.157H190.104H190.242V175.719V127.667L202.774 175.747L202.801 175.857H202.94H226.564H226.675L226.703 175.747L239.234 127.667V175.719V175.857H239.373H252.347H252.485V175.719V120.281V120.143H252.347Z" fill="white"/>
|
||||
<path d="M155.663 120.143H155.58L155.552 120.198L139.812 147.557L123.988 120.198L123.96 120.143H123.877H108.911H108.635L108.773 120.364L133.145 162.579V175.719V175.857H133.283H146.257H146.396V175.719V162.579L170.767 120.364L170.905 120.143H170.629H155.663Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_113_1244" x1="0" y1="148" x2="296" y2="148" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.09375" stop-color="#FB6E4E"/>
|
||||
<stop offset="1" stop-color="#FC1D60"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="210" height="56" viewBox="0 0 210 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M45.8829 0.142822H45.7169V0.28114V48.637L25.3289 0.225818L25.3012 0.142822H25.1905H13.6272H0.652966H0.514648V0.28114V55.7189V55.8572H0.652966H13.6272H13.7655V55.7189V7.28002L34.2365 55.7742L34.2642 55.8572H34.3748H45.8829H58.8294H58.9677V55.7189V0.28114V0.142822H58.8294H45.8829Z"/>
|
||||
<path d="M209.347 0.142822H184.616H184.477L184.45 0.253483L171.78 48.8583L159.082 0.253483L159.054 0.142822H158.944H134.157H133.991V0.28114V55.7189V55.8572H134.157H147.104H147.242V55.7189V7.66731L159.774 55.7466L159.801 55.8572H159.94H183.564H183.675L183.703 55.7466L196.234 7.66731V55.7189V55.8572H196.373H209.347H209.485V55.7189V0.28114V0.142822H209.347Z"/>
|
||||
<path d="M112.663 0.142822H112.58L112.552 0.198153L96.8116 27.5574L80.988 0.198153L80.9604 0.142822H80.8774H65.9114H65.6348L65.7731 0.364136L90.1447 42.5787V55.7189V55.8572H90.283H103.257H103.396V55.7189V42.5787L127.767 0.364136L127.905 0.142822H127.629H112.663Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M170.7 29.3001C131.7 -9.7999 68.3001 -9.7999 29.3001 29.3001C-9.7999 68.4001 -9.7999 131.7 29.3001 170.7C68.4001 209.8 131.7 209.8 170.7 170.7C209.8 131.7 209.8 68.3001 170.7 29.3001ZM162.1 162.1C127.8 196.4 72.1001 196.4 37.8001 162.1C3.5001 127.8 3.5001 72.1001 37.8001 37.8001C72.1001 3.5001 127.8 3.5001 162.1 37.8001C196.5 72.2001 196.5 127.8 162.1 162.1Z" fill="white"/>
|
||||
<path d="M162.1 37.9C127.8 3.60005 72.1002 3.60005 37.8002 37.9C3.50019 72.2 3.50019 127.9 37.8002 162.2C72.1002 196.5 127.8 196.5 162.1 162.2C196.5 127.8 196.5 72.2 162.1 37.9ZM63.0002 170.7C56.8002 167.4 51.1002 163.2 46.1002 158.4V41.7C51.3002 36.7 57.2002 32.5 63.6002 29.1L137 140.9V29.3C143.2 32.6 148.9 36.8 153.9 41.6V158.3C148.7 163.3 142.8 167.5 136.4 170.9L63.0002 59.1V170.7Z" fill="#070B15"/>
|
||||
<path d="M154 158.3V41.7C148.9 36.9 143.2 32.7 137.1 29.4V140.9L63.5 29C57.1 32.4 51.2 36.6 46 41.6V158.3C51.1 163.1 56.8 167.3 62.9 170.6V59.1L136.5 171C142.9 167.6 148.8 163.3 154 158.3Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M170.7 29.3001C131.7 -9.7999 68.3001 -9.7999 29.3001 29.3001C-9.7999 68.4001 -9.7999 131.7 29.3001 170.7C68.4001 209.8 131.7 209.8 170.7 170.7C209.8 131.7 209.8 68.3001 170.7 29.3001ZM162.1 162.1C127.8 196.4 72.1001 196.4 37.8001 162.1C3.5001 127.8 3.5001 72.1001 37.8001 37.8001C72.1001 3.5001 127.8 3.5001 162.1 37.8001C196.5 72.2001 196.5 127.8 162.1 162.1Z" fill="#141521"/>
|
||||
<path d="M162.1 37.9C127.8 3.60005 72.1002 3.60005 37.8002 37.9C3.50019 72.2 3.50019 127.9 37.8002 162.2C72.1002 196.5 127.8 196.5 162.1 162.2C196.5 127.8 196.5 72.2 162.1 37.9ZM63.0002 170.7C56.8002 167.4 51.1002 163.2 46.1002 158.4V41.7C51.3002 36.7 57.2002 32.5 63.6002 29.1L137 140.9V29.3C143.2 32.6 148.9 36.8 153.9 41.6V158.3C148.7 163.3 142.8 167.5 136.4 170.9L63.0002 59.1V170.7Z" fill="white"/>
|
||||
<path d="M154 158.3V41.7C148.9 36.9 143.2 32.7 137.1 29.4V140.9L63.5 29C57.1 32.4 51.2 36.6 46 41.6V158.3C51.1 163.1 56.8 167.3 62.9 170.6V59.1L136.5 171C142.9 167.6 148.8 163.3 154 158.3Z" fill="#141521"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -2,7 +2,7 @@
|
||||
name = "client-core"
|
||||
version = "0.12.0"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -79,9 +79,9 @@ impl KeyManager {
|
||||
))?;
|
||||
|
||||
let gateway_shared_key: SharedKeys =
|
||||
pemstore::load_key(&client_pathfinder.gateway_shared_key().to_owned())?;
|
||||
pemstore::load_key(client_pathfinder.gateway_shared_key())?;
|
||||
|
||||
let ack_key: AckKey = pemstore::load_key(&client_pathfinder.ack_key().to_owned())?;
|
||||
let ack_key: AckKey = pemstore::load_key(client_pathfinder.ack_key())?;
|
||||
|
||||
// TODO: ack key is never stored so it is generated now. But perhaps it should be stored
|
||||
// after all for consistency sake?
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::generic_array::typenum::Unsigned;
|
||||
use log::*;
|
||||
use nymsphinx::anonymous_replies::{
|
||||
encryption_key::EncryptionKeyDigest, encryption_key::Unsigned, SurbEncryptionKey,
|
||||
SurbEncryptionKeySize,
|
||||
encryption_key::EncryptionKeyDigest, SurbEncryptionKey, SurbEncryptionKeySize,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
@@ -43,7 +43,7 @@ impl ReplyKeyStorage {
|
||||
// if this fails it means we have some database corruption and we
|
||||
// absolutely can't continue
|
||||
|
||||
if key_bytes_ref.len() != SurbEncryptionKeySize::to_usize() {
|
||||
if key_bytes_ref.len() != SurbEncryptionKeySize::USIZE {
|
||||
error!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
||||
panic!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
||||
}
|
||||
@@ -59,7 +59,7 @@ impl ReplyKeyStorage {
|
||||
) -> Result<(), ReplyKeyStorageError> {
|
||||
let digest = encryption_key.compute_digest();
|
||||
|
||||
let insertion_result = match self.db.insert(digest.to_vec(), encryption_key.to_bytes()) {
|
||||
let insertion_result = match self.db.insert(digest, encryption_key.to_bytes()) {
|
||||
Err(e) => Err(ReplyKeyStorageError::DbWriteError(e)),
|
||||
Ok(existing_key) => {
|
||||
if existing_key.is_some() {
|
||||
@@ -79,7 +79,7 @@ impl ReplyKeyStorage {
|
||||
&self,
|
||||
key_digest: EncryptionKeyDigest,
|
||||
) -> Result<Option<SurbEncryptionKey>, ReplyKeyStorageError> {
|
||||
let removal_result = match self.db.remove(&key_digest.to_vec()) {
|
||||
let removal_result = match self.db.remove(key_digest) {
|
||||
Err(e) => Err(ReplyKeyStorageError::DbReadError(e)),
|
||||
Ok(existing_key) => {
|
||||
Ok(existing_key.map(|existing_key| self.read_encryption_key(existing_key)))
|
||||
|
||||
@@ -121,12 +121,16 @@ impl<T: NymConfig> Config<T> {
|
||||
self.client.testnet_mode = testnet_mode;
|
||||
}
|
||||
|
||||
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
||||
self.client.gateway_id = id.into();
|
||||
pub fn with_gateway_endpoint<S: Into<String>>(&mut self, id: S, owner: S, listener: S) {
|
||||
self.client.gateway_endpoint = GatewayEndpoint {
|
||||
gateway_id: id.into(),
|
||||
gateway_owner: owner.into(),
|
||||
gateway_listener: listener.into(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn with_gateway_listener<S: Into<String>>(&mut self, gateway_listener: S) {
|
||||
self.client.gateway_listener = gateway_listener.into();
|
||||
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
||||
self.client.gateway_endpoint.gateway_id = id.into();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
@@ -198,11 +202,15 @@ impl<T: NymConfig> Config<T> {
|
||||
}
|
||||
|
||||
pub fn get_gateway_id(&self) -> String {
|
||||
self.client.gateway_id.clone()
|
||||
self.client.gateway_endpoint.gateway_id.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_owner(&self) -> String {
|
||||
self.client.gateway_endpoint.gateway_owner.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_listener(&self) -> String {
|
||||
self.client.gateway_listener.clone()
|
||||
self.client.gateway_endpoint.gateway_listener.clone()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
@@ -272,6 +280,19 @@ impl<T: NymConfig> Default for Config<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
struct GatewayEndpoint {
|
||||
/// gateway_id specifies ID of the gateway to which the client should send messages.
|
||||
/// If initially omitted, a random gateway will be chosen from the available topology.
|
||||
gateway_id: String,
|
||||
|
||||
/// Address of the gateway owner to which the client should send messages.
|
||||
gateway_owner: String,
|
||||
|
||||
/// Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct Client<T> {
|
||||
/// Version of the client for which this configuration was created.
|
||||
@@ -313,12 +334,8 @@ pub struct Client<T> {
|
||||
/// sent but not received back.
|
||||
reply_encryption_key_store_path: PathBuf,
|
||||
|
||||
/// gateway_id specifies ID of the gateway to which the client should send messages.
|
||||
/// If initially omitted, a random gateway will be chosen from the available topology.
|
||||
gateway_id: String,
|
||||
|
||||
/// Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener: String,
|
||||
/// Information regarding how the client should send data to gateway.
|
||||
gateway_endpoint: GatewayEndpoint,
|
||||
|
||||
/// Path to directory containing public/private keys used for bandwidth token purchase.
|
||||
/// Those are saved in case of emergency, to be able to reclaim bandwidth tokens.
|
||||
@@ -357,8 +374,7 @@ impl<T: NymConfig> Default for Client<T> {
|
||||
gateway_shared_key_file: Default::default(),
|
||||
ack_key_file: Default::default(),
|
||||
reply_encryption_key_store_path: Default::default(),
|
||||
gateway_id: "".to_string(),
|
||||
gateway_listener: "".to_string(),
|
||||
gateway_endpoint: Default::default(),
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
backup_bandwidth_token_keys_dir: Default::default(),
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "nym-client"
|
||||
version = "0.12.1"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -2441,9 +2441,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
|
||||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -3806,9 +3806,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.1.23",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
|
||||
"integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
|
||||
"integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
@@ -3943,9 +3943,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nth-check": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz",
|
||||
"integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
|
||||
"integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
|
||||
"dependencies": {
|
||||
"boolbase": "^1.0.0"
|
||||
},
|
||||
@@ -6085,9 +6085,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/url-parse": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz",
|
||||
"integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==",
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"querystringify": "^2.1.1",
|
||||
@@ -8853,9 +8853,9 @@
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
|
||||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"dev": true
|
||||
},
|
||||
"for-in": {
|
||||
@@ -9871,9 +9871,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.1.23",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
|
||||
"integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
|
||||
"integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
@@ -9984,9 +9984,9 @@
|
||||
}
|
||||
},
|
||||
"nth-check": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz",
|
||||
"integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
|
||||
"integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
|
||||
"requires": {
|
||||
"boolbase": "^1.0.0"
|
||||
}
|
||||
@@ -11733,9 +11733,9 @@
|
||||
}
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz",
|
||||
"integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==",
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"querystringify": "^2.1.1",
|
||||
|
||||
@@ -35,7 +35,7 @@ async fn send_file_with_reply() {
|
||||
let (mut ws_stream, _) = connect_async(uri).await.unwrap();
|
||||
|
||||
let recipient = get_self_address(&mut ws_stream).await;
|
||||
println!("our full address is: {}", recipient.to_string());
|
||||
println!("our full address is: {}", recipient);
|
||||
|
||||
let read_data = std::fs::read("examples/dummy_file").unwrap();
|
||||
|
||||
@@ -83,7 +83,7 @@ async fn send_file_without_reply() {
|
||||
let (mut ws_stream, _) = connect_async(uri).await.unwrap();
|
||||
|
||||
let recipient = get_self_address(&mut ws_stream).await;
|
||||
println!("our full address is: {}", recipient.to_string());
|
||||
println!("our full address is: {}", recipient);
|
||||
|
||||
let read_data = std::fs::read("examples/dummy_file").unwrap();
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ async fn send_text_with_reply() {
|
||||
let (mut ws_stream, _) = connect_async(uri).await.unwrap();
|
||||
|
||||
let recipient = get_self_address(&mut ws_stream).await;
|
||||
println!("our full address is: {}", recipient.to_string());
|
||||
println!("our full address is: {}", recipient);
|
||||
|
||||
let send_request = json!({
|
||||
"type" : "send",
|
||||
@@ -76,7 +76,7 @@ async fn send_text_without_reply() {
|
||||
let (mut ws_stream, _) = connect_async(uri).await.unwrap();
|
||||
|
||||
let recipient = get_self_address(&mut ws_stream).await;
|
||||
println!("our full address is: {}", recipient.to_string());
|
||||
println!("our full address is: {}", recipient);
|
||||
|
||||
let send_request = json!({
|
||||
"type" : "send",
|
||||
|
||||
@@ -59,12 +59,6 @@ eth_endpoint = '{{ client.eth_endpoint }}'
|
||||
|
||||
##### additional client config options #####
|
||||
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_id }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_listener }}'
|
||||
|
||||
# A gateway specific, optional, base58 stringified shared key used for
|
||||
# communication with particular gateway.
|
||||
gateway_shared_key_file = '{{ client.gateway_shared_key_file }}'
|
||||
@@ -78,6 +72,17 @@ ack_key_file = '{{ client.ack_key_file }}'
|
||||
# Absolute path to the home Nym Clients directory.
|
||||
nym_root_directory = '{{ client.nym_root_directory }}'
|
||||
|
||||
[client.gateway_endpoint]
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_endpoint.gateway_id }}'
|
||||
|
||||
# Address of the gateway owner to which the client should send messages.
|
||||
gateway_owner = '{{ client.gateway_endpoint.gateway_owner }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_endpoint.gateway_listener }}'
|
||||
|
||||
|
||||
|
||||
##### socket config options #####
|
||||
|
||||
|
||||
@@ -160,6 +160,10 @@ impl NymClient {
|
||||
if gateway_id.is_empty() {
|
||||
panic!("The identity of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_owner = self.config.get_base().get_gateway_owner();
|
||||
if gateway_owner.is_empty() {
|
||||
panic!("The owner of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_address = self.config.get_base().get_gateway_listener();
|
||||
if gateway_address.is_empty() {
|
||||
panic!("The address of the gateway is unknown - did you run `nym-client` init?")
|
||||
@@ -185,6 +189,7 @@ impl NymClient {
|
||||
gateway_address,
|
||||
self.key_manager.identity_keypair(),
|
||||
gateway_identity,
|
||||
gateway_owner,
|
||||
Some(self.key_manager.gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
|
||||
@@ -136,6 +136,7 @@ async fn register_with_gateway(
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
@@ -255,15 +256,14 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_id(gateway_details.identity_key.to_base58_string());
|
||||
let shared_keys =
|
||||
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_details.clients_address());
|
||||
config.get_base_mut().with_gateway_endpoint(
|
||||
gateway_details.identity_key.to_base58_string(),
|
||||
gateway_details.owner.clone(),
|
||||
gateway_details.clients_address(),
|
||||
);
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
|
||||
@@ -32,7 +32,7 @@ fn parse_validators(raw: &str) -> Vec<Url> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> Config {
|
||||
if let Some(raw_validators) = matches.value_of("validators") {
|
||||
config
|
||||
.get_base_mut()
|
||||
@@ -58,7 +58,7 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||
} else {
|
||||
} else if !cfg!(feature = "eth") {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
||||
@@ -66,7 +66,7 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||
} else {
|
||||
} else if !cfg!(feature = "eth") {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
||||
|
||||
@@ -95,7 +95,7 @@ fn parse_package_version() -> Version {
|
||||
|
||||
fn minor_0_12_upgrade(
|
||||
mut config: Config,
|
||||
_matches: &ArgMatches,
|
||||
_matches: &ArgMatches<'_>,
|
||||
config_version: &Version,
|
||||
package_version: &Version,
|
||||
) -> Config {
|
||||
@@ -131,7 +131,7 @@ fn minor_0_12_upgrade(
|
||||
config
|
||||
}
|
||||
|
||||
fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version) {
|
||||
fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: Version) {
|
||||
loop {
|
||||
let config_version = parse_config_version(&config);
|
||||
|
||||
@@ -151,7 +151,7 @@ fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
pub fn execute(matches: &ArgMatches<'_>) {
|
||||
let package_version = parse_package_version();
|
||||
|
||||
let id = matches.value_of("id").unwrap();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "websocket-requests"
|
||||
version = "0.1.0"
|
||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "nym-socks5-client"
|
||||
version = "0.12.1"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -59,12 +59,6 @@ eth_endpoint = '{{ client.eth_endpoint }}'
|
||||
|
||||
##### additional client config options #####
|
||||
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_id }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_listener }}'
|
||||
|
||||
# A gateway specific, optional, base58 stringified shared key used for
|
||||
# communication with particular gateway.
|
||||
gateway_shared_key_file = '{{ client.gateway_shared_key_file }}'
|
||||
@@ -72,12 +66,22 @@ gateway_shared_key_file = '{{ client.gateway_shared_key_file }}'
|
||||
# Path to file containing key used for encrypting and decrypting the content of an
|
||||
# acknowledgement so that nobody besides the client knows which packet it refers to.
|
||||
ack_key_file = '{{ client.ack_key_file }}'
|
||||
|
||||
|
||||
##### advanced configuration options #####
|
||||
|
||||
# Absolute path to the home Nym Clients directory.
|
||||
nym_root_directory = '{{ client.nym_root_directory }}'
|
||||
|
||||
[client.gateway_endpoint]
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_endpoint.gateway_id }}'
|
||||
|
||||
# Address of the gateway owner to which the client should send messages.
|
||||
gateway_owner = '{{ client.gateway_endpoint.gateway_owner }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_endpoint.gateway_listener }}'
|
||||
|
||||
|
||||
##### socket config options #####
|
||||
|
||||
|
||||
@@ -148,6 +148,10 @@ impl NymClient {
|
||||
if gateway_id.is_empty() {
|
||||
panic!("The identity of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_owner = self.config.get_base().get_gateway_owner();
|
||||
if gateway_owner.is_empty() {
|
||||
panic!("The owner of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_address = self.config.get_base().get_gateway_listener();
|
||||
if gateway_address.is_empty() {
|
||||
panic!("The address of the gateway is unknown - did you run `nym-client` init?")
|
||||
@@ -173,6 +177,7 @@ impl NymClient {
|
||||
gateway_address,
|
||||
self.key_manager.identity_keypair(),
|
||||
gateway_identity,
|
||||
gateway_owner,
|
||||
Some(self.key_manager.gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
|
||||
@@ -136,6 +136,7 @@ async fn register_with_gateway(
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
@@ -256,15 +257,14 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_id(gateway_details.identity_key.to_base58_string());
|
||||
let shared_keys =
|
||||
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_details.clients_address());
|
||||
config.get_base_mut().with_gateway_endpoint(
|
||||
gateway_details.identity_key.to_base58_string(),
|
||||
gateway_details.owner.clone(),
|
||||
gateway_details.clients_address(),
|
||||
);
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
|
||||
@@ -32,7 +32,7 @@ fn parse_validators(raw: &str) -> Vec<Url> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> Config {
|
||||
if let Some(raw_validators) = matches.value_of("validators") {
|
||||
config
|
||||
.get_base_mut()
|
||||
@@ -54,7 +54,7 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||
} else {
|
||||
} else if !cfg!(feature = "eth") {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
||||
@@ -62,7 +62,7 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||
} else {
|
||||
} else if !cfg!(feature = "eth") {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
||||
|
||||
@@ -95,7 +95,7 @@ fn parse_package_version() -> Version {
|
||||
|
||||
fn minor_0_12_upgrade(
|
||||
mut config: Config,
|
||||
_matches: &ArgMatches,
|
||||
_matches: &ArgMatches<'_>,
|
||||
config_version: &Version,
|
||||
package_version: &Version,
|
||||
) -> Config {
|
||||
@@ -131,7 +131,7 @@ fn minor_0_12_upgrade(
|
||||
config
|
||||
}
|
||||
|
||||
fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version) {
|
||||
fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: Version) {
|
||||
loop {
|
||||
let config_version = parse_config_version(&config);
|
||||
|
||||
@@ -151,7 +151,7 @@ fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
pub fn execute(matches: &ArgMatches<'_>) {
|
||||
let package_version = parse_package_version();
|
||||
|
||||
let id = matches.value_of("id").unwrap();
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"@rollup/plugin-node-resolve": "^8.0.0",
|
||||
"@rollup/plugin-replace": "^2.4.0",
|
||||
"@rollup/plugin-url": "^5.0.0",
|
||||
"@tauri-apps/cli": "^1.0.0-beta.5",
|
||||
"@tauri-apps/cli": "^1.0.0-rc.5",
|
||||
"rollup": "^2.3.4",
|
||||
"rollup-plugin-svelte": "^7.0.0",
|
||||
"rollup-plugin-terser": "^7.0.0",
|
||||
|
||||
@@ -6,21 +6,25 @@ authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
default-run = "app"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
build = "src/build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.0.0-beta.2" }
|
||||
tauri-build = { version = "=1.0.0-rc.2" }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.0.0-beta.4", features = [] }
|
||||
tauri = { version = "=1.0.0-rc.2", features = [] }
|
||||
tokio = "1.4"
|
||||
url = "2.2"
|
||||
|
||||
tauri-codegen = "=1.0.0-rc.1"
|
||||
tauri-macros = "=1.0.0-rc.1"
|
||||
core-graphics = "=0.22.2"
|
||||
|
||||
coconut-interface = { path = "../../../common/coconut-interface" }
|
||||
credentials = { path = "../../../common/credentials" }
|
||||
validator-client = {path = "../../../common/client-libs/validator-client"}
|
||||
|
||||
@@ -64,15 +64,23 @@ export default class ValidatorClient implements INymClient {
|
||||
|
||||
readonly vestingContract: string;
|
||||
|
||||
readonly mainnetDenom = "unym";
|
||||
|
||||
readonly mainnetPrefix = "n";
|
||||
|
||||
private constructor(
|
||||
client: SigningClient | QueryClient,
|
||||
prefix: string,
|
||||
mixnetContract: string,
|
||||
vestingContract: string,
|
||||
vestingContract: string
|
||||
) {
|
||||
this.client = client;
|
||||
this.prefix = prefix;
|
||||
this.denom = `u${prefix}`;
|
||||
if (prefix == this.mainnetPrefix) {
|
||||
this.denom = this.mainnetDenom;
|
||||
} else {
|
||||
this.denom = `u${prefix}`;
|
||||
}
|
||||
|
||||
this.mixnetContract = mixnetContract;
|
||||
this.vestingContract = vestingContract;
|
||||
@@ -180,8 +188,8 @@ export default class ValidatorClient implements INymClient {
|
||||
return this.client.getSybilResistancePercent(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getEpochRewardPercent(): Promise<number> {
|
||||
return this.client.getEpochRewardPercent(this.mixnetContract);
|
||||
public async getIntervalRewardPercent(): Promise<number> {
|
||||
return this.client.getIntervalRewardPercent(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getAllNymdMixnodes(): Promise<MixNodeBond[]> {
|
||||
@@ -433,6 +441,14 @@ export default class ValidatorClient implements INymClient {
|
||||
return (this.client as ISigningClient).undelegateFromMixNode(this.mixnetContract, mixIdentity, fee, memo);
|
||||
}
|
||||
|
||||
public async updateMixnodeConfig(
|
||||
mixIdentity: string,
|
||||
fee: StdFee | 'auto' | number,
|
||||
profitPercentage: number,
|
||||
): Promise<ExecuteResult> {
|
||||
return (this.client as ISigningClient).updateMixnodeConfig(this.mixnetContract, mixIdentity, profitPercentage, fee);
|
||||
}
|
||||
|
||||
public async updateContractStateParams(
|
||||
newParams: ContractStateParams,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
@@ -441,4 +457,4 @@ export default class ValidatorClient implements INymClient {
|
||||
this.assertSigning();
|
||||
return (this.client as ISigningClient).updateContractStateParams(this.mixnetContract, newParams, fee, memo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
RewardingIntervalResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
|
||||
@@ -79,12 +78,6 @@ export default class NymdQuerier implements INymdQuery {
|
||||
});
|
||||
}
|
||||
|
||||
getCurrentRewardingInterval(mixnetContractAddress: string): Promise<RewardingIntervalResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
current_rewarding_interval: {},
|
||||
});
|
||||
}
|
||||
|
||||
getAllNetworkDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
@@ -155,9 +148,9 @@ export default class NymdQuerier implements INymdQuery {
|
||||
});
|
||||
}
|
||||
|
||||
getEpochRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_epoch_reward_percent: {},
|
||||
get_interval_reward_percent: {},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import {
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
RewardingIntervalResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
import ValidatorApiQuerier, { IValidatorApiQuery } from './validator-api-querier';
|
||||
@@ -63,7 +62,6 @@ export interface INymdQuery {
|
||||
ownsMixNode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse>;
|
||||
ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse>;
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractStateParams>;
|
||||
getCurrentRewardingInterval(mixnetContractAddress: string): Promise<RewardingIntervalResponse>;
|
||||
|
||||
getAllNetworkDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
@@ -87,7 +85,7 @@ export interface INymdQuery {
|
||||
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution>;
|
||||
getRewardPool(mixnetContractAddress: string): Promise<string>;
|
||||
getCirculatingSupply(mixnetContractAddress: string): Promise<string>;
|
||||
getEpochRewardPercent(mixnetContractAddress: string): Promise<number>;
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number>;
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number>;
|
||||
getRewardingStatus(
|
||||
mixnetContractAddress: string,
|
||||
@@ -138,10 +136,6 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
|
||||
return this.nymdQuerier.getStateParams(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getCurrentRewardingInterval(mixnetContractAddress: string): Promise<RewardingIntervalResponse> {
|
||||
return this.nymdQuerier.getCurrentRewardingInterval(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getAllNetworkDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
@@ -184,8 +178,8 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
|
||||
return this.nymdQuerier.getCirculatingSupply(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getEpochRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nymdQuerier.getEpochRewardPercent(mixnetContractAddress);
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nymdQuerier.getIntervalRewardPercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
|
||||
|
||||
@@ -31,7 +31,6 @@ import {
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
RewardingIntervalResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
import ValidatorApiQuerier from './validator-api-querier';
|
||||
@@ -178,6 +177,13 @@ export interface ISigningClient extends IQueryClient, ICosmWasmSigning, INymSign
|
||||
memo?: string,
|
||||
): Promise<ExecuteResult>;
|
||||
|
||||
updateMixnodeConfig(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
profitMarginPercent: number,
|
||||
fee: StdFee | 'auto' | number,
|
||||
): Promise<ExecuteResult>;
|
||||
|
||||
updateContractStateParams(
|
||||
mixnetContractAddress: string,
|
||||
newParams: ContractStateParams,
|
||||
@@ -250,10 +256,6 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
return this.nymdQuerier.getStateParams(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getCurrentRewardingInterval(mixnetContractAddress: string): Promise<RewardingIntervalResponse> {
|
||||
return this.nymdQuerier.getCurrentRewardingInterval(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getAllNetworkDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
@@ -296,8 +298,8 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
return this.nymdQuerier.getCirculatingSupply(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getEpochRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nymdQuerier.getEpochRewardPercent(mixnetContractAddress);
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nymdQuerier.getIntervalRewardPercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
|
||||
@@ -448,6 +450,20 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
);
|
||||
}
|
||||
|
||||
updateMixnodeConfig(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
profitMarginPercent: number,
|
||||
fee: StdFee | 'auto' | number,
|
||||
): Promise<ExecuteResult> {
|
||||
return this.execute(
|
||||
this.clientAddress,
|
||||
mixnetContractAddress,
|
||||
{ update_mixnode_config: { profit_margin_percent: profitMarginPercent, mix_identity: mixIdentity } },
|
||||
fee,
|
||||
);
|
||||
}
|
||||
|
||||
updateContractStateParams(
|
||||
mixnetContractAddress: string,
|
||||
newParams: ContractStateParams,
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
import axios from 'axios';
|
||||
import { GasPrice } from '@cosmjs/stargate';
|
||||
|
||||
const mainnetPrefix = 'n';
|
||||
const mainnetDenom = 'nym';
|
||||
|
||||
export function nymGasPrice(prefix: string): GasPrice {
|
||||
return GasPrice.fromString(`0.025u${prefix}`); // TODO: ideally this ugly conversion shouldn't be hardcoded here.
|
||||
if (typeof prefix === 'string') {
|
||||
if (prefix === mainnetPrefix) {
|
||||
prefix = mainnetDenom;
|
||||
}
|
||||
return GasPrice.fromString(`0.025u${prefix}`); // TODO: ideally this ugly conversion shouldn't be hardcoded here.
|
||||
}
|
||||
else {
|
||||
throw new Error(`${prefix} is not of type string`);
|
||||
}
|
||||
}
|
||||
|
||||
export const downloadWasm = async (url: string): Promise<Uint8Array> => {
|
||||
|
||||
@@ -43,12 +43,6 @@ export type ContractStateParams = {
|
||||
mixnode_active_set_size: number;
|
||||
};
|
||||
|
||||
export type RewardingIntervalResponse = {
|
||||
current_rewarding_interval_starting_block: number;
|
||||
current_rewarding_interval_nonce: number;
|
||||
rewarding_in_progress: boolean;
|
||||
};
|
||||
|
||||
export type LayerDistribution = {
|
||||
gateways: number;
|
||||
layer1: number;
|
||||
@@ -135,6 +129,7 @@ export type MixNode = {
|
||||
sphinx_key: string;
|
||||
identity_key: string;
|
||||
version: string;
|
||||
profit_margin_percent: number;
|
||||
};
|
||||
|
||||
export type GatewayBond = {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "nym-client-wasm"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||
version = "0.12.0"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/nymtech/nym"
|
||||
@@ -20,7 +20,7 @@ coconut = ["coconut-interface", "credentials", "gateway-client/coconut"]
|
||||
[dependencies]
|
||||
futures = "0.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
|
||||
wasm-bindgen = { version = "=0.2.78", features = ["serde-serialize"] }
|
||||
wasm-bindgen-futures = "0.4"
|
||||
js-sys = "0.3"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
@@ -32,7 +32,7 @@ credentials = { path = "../../common/credentials", optional = true }
|
||||
crypto = { path = "../../common/crypto" }
|
||||
nymsphinx = { path = "../../common/nymsphinx" }
|
||||
topology = { path = "../../common/topology" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm"] }
|
||||
validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
|
||||
wasm-utils = { path = "../../common/wasm-utils" }
|
||||
|
||||
|
||||
@@ -22,7 +22,10 @@
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
}
|
||||
},
|
||||
"../pkg": {},
|
||||
"../pkg": {
|
||||
"name": "@nymproject/nym-client-wasm",
|
||||
"version": "0.0.1"
|
||||
},
|
||||
"node_modules/@nymproject/nym-client-wasm": {
|
||||
"resolved": "../pkg",
|
||||
"link": true
|
||||
@@ -2351,9 +2354,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
|
||||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -5859,9 +5862,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/url-parse": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz",
|
||||
"integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==",
|
||||
"version": "1.5.7",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz",
|
||||
"integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"querystringify": "^2.1.1",
|
||||
@@ -6500,9 +6503,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
|
||||
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
|
||||
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"async-limiter": "~1.0.0"
|
||||
@@ -8542,9 +8545,9 @@
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
|
||||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"dev": true
|
||||
},
|
||||
"for-in": {
|
||||
@@ -11399,9 +11402,9 @@
|
||||
}
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz",
|
||||
"integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==",
|
||||
"version": "1.5.7",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz",
|
||||
"integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"querystringify": "^2.1.1",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"@testing-library/react": "^9.5.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
"bootstrap": "^4.5.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"node-sass": "^7.0.0",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-scripts": "^4.0.0",
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use futures::channel::mpsc;
|
||||
use gateway_client::bandwidth::BandwidthController;
|
||||
use gateway_client::GatewayClient;
|
||||
use nymsphinx::acknowledgements::AckKey;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
@@ -111,7 +110,7 @@ impl NymClient {
|
||||
let testnet_mode = self.testnet_mode;
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
let bandwidth_controller = Some(BandwidthController::new(
|
||||
let bandwidth_controller = Some(gateway_client::bandwidth::BandwidthController::new(
|
||||
vec![self.validator_server.clone()],
|
||||
*self.identity.public_key(),
|
||||
));
|
||||
@@ -128,6 +127,7 @@ impl NymClient {
|
||||
gateway.clients_address(),
|
||||
Arc::clone(&client.identity),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
None,
|
||||
mixnet_messages_sender,
|
||||
ack_sender,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "bandwidth-claim-contract"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "gateway-client"
|
||||
version = "0.1.0"
|
||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -15,12 +15,15 @@ log = "0.4"
|
||||
thiserror = "1.0"
|
||||
url = "2.2"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
secp256k1 = "0.20.3"
|
||||
web3 = { version = "0.17.0", default-features = false }
|
||||
|
||||
# internal
|
||||
credentials = { path = "../../credentials" }
|
||||
crypto = { path = "../../crypto" }
|
||||
gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||
nymsphinx = { path = "../../nymsphinx" }
|
||||
pemstore = { path = "../../pemstore" }
|
||||
coconut-interface = { path = "../../coconut-interface", optional = true }
|
||||
network-defaults = { path = "../../network-defaults" }
|
||||
|
||||
@@ -36,12 +39,6 @@ features = ["macros", "rt", "net", "sync", "time"]
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
|
||||
version = "0.14"
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.secp256k1]
|
||||
version = "0.20.3"
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.web3]
|
||||
version = "0.17.0"
|
||||
|
||||
# wasm-only dependencies
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
|
||||
version = "0.2"
|
||||
@@ -70,4 +67,6 @@ features = ["js"]
|
||||
#url = "2.1"
|
||||
|
||||
[features]
|
||||
coconut = ["gateway-requests/coconut", "coconut-interface"]
|
||||
coconut = ["gateway-requests/coconut", "coconut-interface"]
|
||||
wasm = ["web3/wasm", "web3/http", "web3/signing"]
|
||||
default = ["web3/default"]
|
||||
@@ -16,22 +16,27 @@ use crypto::asymmetric::identity::PublicKey;
|
||||
use network_defaults::BANDWIDTH_VALUE;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use network_defaults::{
|
||||
eth_contract::ETH_JSON_ABI, ETH_BURN_FUNCTION_NAME, ETH_CONTRACT_ADDRESS, ETH_MIN_BLOCK_DEPTH,
|
||||
TOKENS_TO_BURN,
|
||||
eth_contract::ETH_ERC20_JSON_ABI, eth_contract::ETH_JSON_ABI, ETH_BURN_FUNCTION_NAME,
|
||||
ETH_CONTRACT_ADDRESS, ETH_ERC20_APPROVE_FUNCTION_NAME, ETH_ERC20_CONTRACT_ADDRESS,
|
||||
ETH_MIN_BLOCK_DEPTH, TOKENS_TO_BURN, UTOKENS_TO_BURN,
|
||||
};
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use pemstore::traits::PemStorableKeyPair;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use rand::rngs::OsRng;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use secp256k1::SecretKey;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use std::io::Write;
|
||||
use std::io::{Read, Write};
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use std::str::FromStr;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use web3::{
|
||||
contract::{Contract, Options},
|
||||
ethabi::Token,
|
||||
signing::{Key, SecretKeyRef},
|
||||
transports::Http,
|
||||
types::{Address, Bytes, U256, U64},
|
||||
types::{Address, U256, U64},
|
||||
Web3,
|
||||
};
|
||||
|
||||
@@ -50,6 +55,19 @@ pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> {
|
||||
.expect("Invalid json abi")
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub fn eth_erc20_contract(web3: Web3<Http>) -> Contract<Http> {
|
||||
Contract::from_json(
|
||||
web3.eth(),
|
||||
Address::from(ETH_ERC20_CONTRACT_ADDRESS),
|
||||
json::parse(ETH_ERC20_JSON_ABI)
|
||||
.expect("Invalid json abi")
|
||||
.dump()
|
||||
.as_bytes(),
|
||||
)
|
||||
.expect("Invalid json abi")
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BandwidthController {
|
||||
#[cfg(feature = "coconut")]
|
||||
@@ -59,6 +77,8 @@ pub struct BandwidthController {
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
contract: Contract<Http>,
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
erc20_contract: Contract<Http>,
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
eth_private_key: SecretKey,
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
backup_bandwidth_token_keys_dir: std::path::PathBuf,
|
||||
@@ -84,12 +104,14 @@ impl BandwidthController {
|
||||
Http::new(ð_endpoint).map_err(|_| GatewayClientError::InvalidURL(eth_endpoint))?;
|
||||
let web3 = web3::Web3::new(transport);
|
||||
// Fail early, on invalid abi
|
||||
let contract = eth_contract(web3);
|
||||
let contract = eth_contract(web3.clone());
|
||||
let erc20_contract = eth_erc20_contract(web3);
|
||||
let eth_private_key = secp256k1::SecretKey::from_str(ð_private_key)
|
||||
.map_err(|_| GatewayClientError::InvalidEthereumPrivateKey)?;
|
||||
|
||||
Ok(BandwidthController {
|
||||
contract,
|
||||
erc20_contract,
|
||||
eth_private_key,
|
||||
backup_bandwidth_token_keys_dir,
|
||||
})
|
||||
@@ -107,6 +129,45 @@ impl BandwidthController {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
fn restore_keypair(&self) -> Result<identity::KeyPair, GatewayClientError> {
|
||||
std::fs::create_dir_all(&self.backup_bandwidth_token_keys_dir)?;
|
||||
let file = std::fs::read_dir(&self.backup_bandwidth_token_keys_dir)?
|
||||
.find(|entry| {
|
||||
entry
|
||||
.as_ref()
|
||||
.map(|entry| entry.path().is_file())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.unwrap_or_else(|| Err(std::io::Error::from(std::io::ErrorKind::NotFound)))?;
|
||||
let file_path = file.path();
|
||||
let pub_key = file_path
|
||||
.file_name()
|
||||
.ok_or_else(|| std::io::Error::from(std::io::ErrorKind::NotFound))?
|
||||
.to_str()
|
||||
.ok_or_else(|| std::io::Error::from(std::io::ErrorKind::NotFound))?;
|
||||
let mut priv_key = vec![];
|
||||
std::fs::File::open(file_path.clone())?.read_to_end(&mut priv_key)?;
|
||||
Ok(identity::KeyPair::from_keys(
|
||||
identity::PrivateKey::from_bytes(&priv_key).unwrap(),
|
||||
identity::PublicKey::from_base58_string(pub_key).unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
fn mark_keypair_as_spent(&self, keypair: &identity::KeyPair) -> Result<(), GatewayClientError> {
|
||||
let mut spent_dir = self.backup_bandwidth_token_keys_dir.clone();
|
||||
spent_dir.push("spent");
|
||||
std::fs::create_dir_all(&spent_dir)?;
|
||||
let file_path_old = self
|
||||
.backup_bandwidth_token_keys_dir
|
||||
.join(keypair.public_key().to_base58_string());
|
||||
let file_path_new = spent_dir.join(keypair.public_key().to_base58_string());
|
||||
std::fs::rename(file_path_old, file_path_new)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
pub async fn prepare_coconut_credential(
|
||||
&self,
|
||||
@@ -145,17 +206,25 @@ impl BandwidthController {
|
||||
pub async fn prepare_token_credential(
|
||||
&self,
|
||||
gateway_identity: PublicKey,
|
||||
gateway_owner: String,
|
||||
) -> Result<TokenCredential, GatewayClientError> {
|
||||
let mut rng = OsRng;
|
||||
|
||||
let kp = identity::KeyPair::new(&mut rng);
|
||||
self.backup_keypair(&kp)?;
|
||||
let kp = match self.restore_keypair() {
|
||||
Ok(kp) => kp,
|
||||
Err(_) => {
|
||||
let mut rng = OsRng;
|
||||
let kp = identity::KeyPair::new(&mut rng);
|
||||
self.backup_keypair(&kp)?;
|
||||
kp
|
||||
}
|
||||
};
|
||||
|
||||
let verification_key = *kp.public_key();
|
||||
let signed_verification_key = kp.private_key().sign(&verification_key.to_bytes());
|
||||
self.buy_token_credential(verification_key, signed_verification_key)
|
||||
self.buy_token_credential(verification_key, signed_verification_key, gateway_owner)
|
||||
.await?;
|
||||
|
||||
self.mark_keypair_as_spent(&kp)?;
|
||||
|
||||
let message: Vec<u8> = verification_key
|
||||
.to_bytes()
|
||||
.iter()
|
||||
@@ -177,33 +246,114 @@ impl BandwidthController {
|
||||
&self,
|
||||
verification_key: PublicKey,
|
||||
signed_verification_key: identity::Signature,
|
||||
gateway_owner: String,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
// 0 means a transaction failure, 1 means success
|
||||
let confirmations = if cfg!(debug_assertions) {
|
||||
1
|
||||
} else {
|
||||
ETH_MIN_BLOCK_DEPTH
|
||||
};
|
||||
// 15 seconds per confirmation block + 10 seconds of network overhead
|
||||
// 15 seconds per confirmation block + 10 seconds of network overhead + 20 seconds of wait for kill
|
||||
log::info!(
|
||||
"Waiting for Ethereum transaction. This should take about {} seconds",
|
||||
confirmations * 15 + 10
|
||||
(confirmations + 1) * 15 + 30
|
||||
);
|
||||
let mut options = Options::default();
|
||||
let estimation = self
|
||||
.erc20_contract
|
||||
.estimate_gas(
|
||||
ETH_ERC20_APPROVE_FUNCTION_NAME,
|
||||
(
|
||||
Token::Address(Address::from(ETH_CONTRACT_ADDRESS)),
|
||||
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||
),
|
||||
SecretKeyRef::from(&self.eth_private_key).address(),
|
||||
options.clone(),
|
||||
)
|
||||
.await?;
|
||||
options.gas = Some(estimation);
|
||||
log::info!("Calling ERC20 approve in 10 seconds with an estimated gas of {}. Kill the process if you want to abort", estimation);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
if let Err(err) = fluvio_wasm_timer::Delay::new(std::time::Duration::from_secs(10)).await {
|
||||
log::error!(
|
||||
"the timer has gone away while waiting for possible kill! - {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
let recipt = self
|
||||
.erc20_contract
|
||||
.signed_call_with_confirmations(
|
||||
ETH_ERC20_APPROVE_FUNCTION_NAME,
|
||||
(
|
||||
Token::Address(Address::from(ETH_CONTRACT_ADDRESS)),
|
||||
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||
),
|
||||
options,
|
||||
1, // One confirmation is enough, as we'll be consuming the approved token next anyway
|
||||
&self.eth_private_key,
|
||||
)
|
||||
.await?;
|
||||
if Some(U64::from(0u64)) == recipt.status {
|
||||
return Err(GatewayClientError::BurnTokenError(
|
||||
web3::Error::InvalidResponse(format!(
|
||||
"Approve transaction status is 0 (failure): {:?}",
|
||||
recipt.logs,
|
||||
)),
|
||||
));
|
||||
} else {
|
||||
log::info!(
|
||||
"Approved {} tokens for bandwidth use on Ethereum",
|
||||
TOKENS_TO_BURN
|
||||
);
|
||||
}
|
||||
|
||||
let mut options = Options::default();
|
||||
let estimation = self
|
||||
.contract
|
||||
.estimate_gas(
|
||||
ETH_BURN_FUNCTION_NAME,
|
||||
(
|
||||
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||
Token::Uint(U256::from(&verification_key.to_bytes())),
|
||||
Token::Bytes(signed_verification_key.to_bytes().to_vec()),
|
||||
Token::String(gateway_owner.clone()),
|
||||
),
|
||||
SecretKeyRef::from(&self.eth_private_key).address(),
|
||||
options.clone(),
|
||||
)
|
||||
.await?;
|
||||
options.gas = Some(estimation);
|
||||
log::info!("Generating bandwidth on ETH contract in 10 seconds with an estimated gas of {}. \
|
||||
Kill the process if you want to abort. Keep in mind that if you abort now, you'll still have \
|
||||
some tokens approved for bandwidth spending from the previous action. \
|
||||
If you don't want that, you'll need to manually decreaseAllowance to revert the approval.", estimation);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
if let Err(err) = fluvio_wasm_timer::Delay::new(std::time::Duration::from_secs(10)).await {
|
||||
log::error!(
|
||||
"the timer has gone away while waiting for possible kill! - {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
let recipt = self
|
||||
.contract
|
||||
.signed_call_with_confirmations(
|
||||
ETH_BURN_FUNCTION_NAME,
|
||||
(
|
||||
U256::from(TOKENS_TO_BURN),
|
||||
U256::from(&verification_key.to_bytes()),
|
||||
Bytes(signed_verification_key.to_bytes().to_vec()),
|
||||
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||
Token::Uint(U256::from(&verification_key.to_bytes())),
|
||||
Token::Bytes(signed_verification_key.to_bytes().to_vec()),
|
||||
Token::String(gateway_owner),
|
||||
),
|
||||
Options::default(),
|
||||
options,
|
||||
confirmations,
|
||||
&self.eth_private_key,
|
||||
)
|
||||
.await?;
|
||||
if Some(U64::from(0)) == recipt.status {
|
||||
if Some(U64::from(0u64)) == recipt.status {
|
||||
Err(GatewayClientError::BurnTokenError(
|
||||
web3::Error::InvalidResponse(format!(
|
||||
"Transaction status is 0 (failure): {:?}",
|
||||
@@ -236,6 +386,15 @@ mod tests {
|
||||
eth_contract(web3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_erc20_contract() {
|
||||
let transport =
|
||||
Http::new("https://rinkeby.infura.io/v3/00000000000000000000000000000000").unwrap();
|
||||
let web3 = web3::Web3::new(transport);
|
||||
// test no panic occurs
|
||||
eth_erc20_contract(web3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_event_name_constant_against_abi() {
|
||||
let transport =
|
||||
|
||||
@@ -20,6 +20,7 @@ use gateway_requests::iv::IV;
|
||||
use gateway_requests::registration::handshake::{client_handshake, SharedKeys};
|
||||
use gateway_requests::{BinaryRequest, ClientControlRequest, ServerResponse};
|
||||
use log::*;
|
||||
use network_defaults::{REMAINING_BANDWIDTH_THRESHOLD, TOKENS_TO_BURN};
|
||||
use nymsphinx::forwarding::packet::MixPacket;
|
||||
use rand::rngs::OsRng;
|
||||
use std::convert::TryFrom;
|
||||
@@ -44,6 +45,7 @@ pub struct GatewayClient {
|
||||
bandwidth_remaining: i64,
|
||||
gateway_address: String,
|
||||
gateway_identity: identity::PublicKey,
|
||||
gateway_owner: String,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
shared_key: Option<Arc<SharedKeys>>,
|
||||
connection: SocketState,
|
||||
@@ -68,6 +70,7 @@ impl GatewayClient {
|
||||
gateway_address: String,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
gateway_identity: identity::PublicKey,
|
||||
gateway_owner: String,
|
||||
shared_key: Option<Arc<SharedKeys>>,
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
@@ -80,6 +83,7 @@ impl GatewayClient {
|
||||
bandwidth_remaining: 0,
|
||||
gateway_address,
|
||||
gateway_identity,
|
||||
gateway_owner,
|
||||
local_identity,
|
||||
shared_key,
|
||||
connection: SocketState::NotConnected,
|
||||
@@ -112,6 +116,7 @@ impl GatewayClient {
|
||||
pub fn new_init(
|
||||
gateway_address: String,
|
||||
gateway_identity: identity::PublicKey,
|
||||
gateway_owner: String,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
response_timeout_duration: Duration,
|
||||
) -> Self {
|
||||
@@ -129,6 +134,7 @@ impl GatewayClient {
|
||||
bandwidth_remaining: 0,
|
||||
gateway_address,
|
||||
gateway_identity,
|
||||
gateway_owner,
|
||||
local_identity,
|
||||
shared_key: None,
|
||||
connection: SocketState::NotConnected,
|
||||
@@ -548,6 +554,8 @@ impl GatewayClient {
|
||||
return self.try_claim_testnet_bandwidth().await;
|
||||
}
|
||||
|
||||
let _gateway_owner = self.gateway_owner.clone();
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
let credential = self
|
||||
.bandwidth_controller
|
||||
@@ -560,7 +568,7 @@ impl GatewayClient {
|
||||
.bandwidth_controller
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.prepare_token_credential(self.gateway_identity)
|
||||
.prepare_token_credential(self.gateway_identity, _gateway_owner)
|
||||
.await?;
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
@@ -584,15 +592,10 @@ impl GatewayClient {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
}
|
||||
if self.estimate_required_bandwidth(&packets) > self.bandwidth_remaining {
|
||||
// Try to claim more bandwidth first, and return an error only if that is still not
|
||||
// enough (the current granularity for bandwidth should be sufficient)
|
||||
self.claim_bandwidth().await?;
|
||||
if self.estimate_required_bandwidth(&packets) > self.bandwidth_remaining {
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
self.estimate_required_bandwidth(&packets),
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
}
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
self.estimate_required_bandwidth(&packets),
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
}
|
||||
if !self.connection.is_established() {
|
||||
return Err(GatewayClientError::ConnectionNotEstablished);
|
||||
@@ -659,15 +662,10 @@ impl GatewayClient {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
}
|
||||
if (mix_packet.sphinx_packet().len() as i64) > self.bandwidth_remaining {
|
||||
// Try to claim more bandwidth first, and return an error only if that is still not
|
||||
// enough
|
||||
self.claim_bandwidth().await?;
|
||||
if (mix_packet.sphinx_packet().len() as i64) > self.bandwidth_remaining {
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
mix_packet.sphinx_packet().len() as i64,
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
}
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
mix_packet.sphinx_packet().len() as i64,
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
}
|
||||
if !self.connection.is_established() {
|
||||
return Err(GatewayClientError::ConnectionNotEstablished);
|
||||
@@ -737,6 +735,12 @@ impl GatewayClient {
|
||||
}
|
||||
let shared_key = self.perform_initial_authentication().await?;
|
||||
|
||||
if self.bandwidth_remaining < REMAINING_BANDWIDTH_THRESHOLD {
|
||||
info!("Claiming more bandwidth for your tokens. This will use {} token(s) from your wallet. \
|
||||
Stop the process now if you don't want that to happen.", TOKENS_TO_BURN);
|
||||
self.claim_bandwidth().await?;
|
||||
}
|
||||
|
||||
// this call is NON-blocking
|
||||
self.start_listening_for_mixnet_messages()?;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use tungstenite::Error as WsError;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_bindgen::JsValue;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use web3::Error as Web3Error;
|
||||
use web3::{contract::Error as Web3ContractError, Error as Web3Error};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GatewayClientError {
|
||||
@@ -27,13 +27,17 @@ pub enum GatewayClientError {
|
||||
NetworkErrorWasm(JsValue),
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[error("Could not backup keypair - {0}")]
|
||||
#[error("Keypair IO error - {0}")]
|
||||
IOError(#[from] std::io::Error),
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[error("Could not burn ERC20 token in Ethereum smart contract - {0}")]
|
||||
BurnTokenError(#[from] Web3Error),
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[error("Could not run web3 contract - {0}")]
|
||||
Web3ContractError(#[from] Web3ContractError),
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[error("Invalid Ethereum private key")]
|
||||
InvalidEthereumPrivateKey,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "mixnet-client"
|
||||
version = "0.1.0"
|
||||
authors = ["Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -41,6 +41,17 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SendWithoutResponse {
|
||||
// Without response in this context means we will not listen for anything we might get back (not
|
||||
// that we should get anything), including any possible io errors
|
||||
fn send_without_response(
|
||||
&mut self,
|
||||
address: NymNodeRoutingAddress,
|
||||
packet: SphinxPacket,
|
||||
packet_mode: PacketMode,
|
||||
) -> io::Result<()>;
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
conn_new: HashMap<NymNodeRoutingAddress, ConnectionSender>,
|
||||
config: Config,
|
||||
@@ -186,10 +197,10 @@ impl Client {
|
||||
.await
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// without response in this context means we will not listen for anything we might get back
|
||||
// (not that we should get anything), including any possible io errors
|
||||
pub fn send_without_response(
|
||||
impl SendWithoutResponse for Client {
|
||||
fn send_without_response(
|
||||
&mut self,
|
||||
address: NymNodeRoutingAddress,
|
||||
packet: SphinxPacket,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::{Client, Config};
|
||||
use crate::client::{Client, Config, SendWithoutResponse};
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
pub mod client;
|
||||
pub mod forwarder;
|
||||
|
||||
pub use client::{Client, Config};
|
||||
pub use client::{Client, Config, SendWithoutResponse};
|
||||
|
||||
@@ -2,24 +2,26 @@
|
||||
name = "validator-client"
|
||||
version = "0.1.0"
|
||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.13"
|
||||
mixnet-contract = { path="../../../common/mixnet-contract" }
|
||||
vesting-contract = { path="../../../contracts/vesting" }
|
||||
serde = { version="1", features=["derive"] }
|
||||
mixnet-contract-common = { path= "../../cosmwasm-smart-contracts/mixnet-contract" }
|
||||
vesting-contract-common = { path= "../../cosmwasm-smart-contracts/vesting-contract" }
|
||||
vesting-contract = { path = "../../../contracts/vesting" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
reqwest = { version="0.11", features=["json"] }
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
thiserror = "1"
|
||||
log = "0.4"
|
||||
url = { version = "2.2", features = ["serde"] }
|
||||
|
||||
coconut-interface = { path = "../../coconut-interface" }
|
||||
network-defaults = { path = "../../network-defaults" }
|
||||
validator-api-requests = { path = "../../../validator-api/validator-api-requests" }
|
||||
|
||||
# required for nymd-client
|
||||
# at some point it might be possible to make it wasm-compatible
|
||||
@@ -27,14 +29,29 @@ network-defaults = { path = "../../network-defaults" }
|
||||
async-trait = { version = "0.1.51", optional = true }
|
||||
bip39 = { version = "1", features = ["rand"], optional = true }
|
||||
config = { path = "../../config", optional = true }
|
||||
#cosmrs = { version = "0.3", features = ["rpc", "bip32", "cosmwasm"], optional = true }
|
||||
cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev="e5a1872083abb3d88fa62dda966e7f5408deba58", features = ["rpc", "bip32", "cosmwasm"], optional = true }
|
||||
cosmrs = { version = "0.4.1", features = [
|
||||
"rpc",
|
||||
"bip32",
|
||||
"cosmwasm",
|
||||
], optional = true }
|
||||
prost = { version = "0.9", default-features = false, optional = true }
|
||||
flate2 = { version = "1.0.20", optional = true }
|
||||
sha2 = { version = "0.9.5", optional = true }
|
||||
itertools = { version = "0.10", optional = true }
|
||||
cosmwasm-std = { version = "1.0.0-beta3", optional = true }
|
||||
ts-rs = {version = "5.1", optional = true}
|
||||
|
||||
[dev-dependencies]
|
||||
ts-rs = "6.1.2"
|
||||
|
||||
[features]
|
||||
nymd-client = ["async-trait", "bip39", "config", "cosmrs", "prost", "flate2", "sha2", "itertools", "cosmwasm-std"]
|
||||
nymd-client = [
|
||||
"async-trait",
|
||||
"bip39",
|
||||
"config",
|
||||
"cosmrs",
|
||||
"prost",
|
||||
"flate2",
|
||||
"sha2",
|
||||
"itertools",
|
||||
"cosmwasm-std",
|
||||
]
|
||||
|
||||
@@ -1,53 +1,71 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{validator_api, ValidatorClientError};
|
||||
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
|
||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, Interval, MixNodeBond};
|
||||
use network_defaults::DEFAULT_NETWORK;
|
||||
use url::Url;
|
||||
use validator_api_requests::models::{
|
||||
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
|
||||
StakeSaturationResponse,
|
||||
};
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use crate::nymd::{
|
||||
error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient,
|
||||
};
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use mixnet_contract::ContractStateParams;
|
||||
use mixnet_contract_common::ContractStateParams;
|
||||
|
||||
use crate::{validator_api, ValidatorClientError};
|
||||
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use mixnet_contract::{
|
||||
Delegation, MixnetContractVersion, MixnodeRewardingStatusResponse, RewardingIntervalResponse,
|
||||
use mixnet_contract_common::{
|
||||
Delegation, IdentityKey, MixnetContractVersion, MixnodeRewardingStatusResponse,
|
||||
RewardedSetNodeStatus, RewardedSetUpdateDetails,
|
||||
};
|
||||
use mixnet_contract::{GatewayBond, MixNodeBond};
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use std::collections::{HashMap, HashSet};
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
#[must_use]
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
network: network_defaults::all::Network,
|
||||
api_url: Url,
|
||||
nymd_url: Url,
|
||||
mixnet_contract_address: Option<cosmrs::AccountId>,
|
||||
vesting_contract_address: Option<cosmrs::AccountId>,
|
||||
erc20_bridge_contract_address: Option<cosmrs::AccountId>,
|
||||
|
||||
mixnode_page_limit: Option<u32>,
|
||||
gateway_page_limit: Option<u32>,
|
||||
mixnode_delegations_page_limit: Option<u32>,
|
||||
rewarded_set_page_limit: Option<u32>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
impl Config {
|
||||
pub fn new(
|
||||
network: network_defaults::all::Network,
|
||||
nymd_url: Url,
|
||||
api_url: Url,
|
||||
mixnet_contract_address: Option<cosmrs::AccountId>,
|
||||
vesting_contract_address: Option<cosmrs::AccountId>,
|
||||
erc20_bridge_contract_address: Option<cosmrs::AccountId>,
|
||||
) -> Self {
|
||||
Config {
|
||||
network,
|
||||
nymd_url,
|
||||
mixnet_contract_address,
|
||||
vesting_contract_address,
|
||||
erc20_bridge_contract_address,
|
||||
api_url,
|
||||
mixnode_page_limit: None,
|
||||
gateway_page_limit: None,
|
||||
mixnode_delegations_page_limit: None,
|
||||
rewarded_set_page_limit: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,17 +83,25 @@ impl Config {
|
||||
self.mixnode_delegations_page_limit = limit;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_rewarded_set_page_limit(mut self, limit: Option<u32>) -> Config {
|
||||
self.rewarded_set_page_limit = limit;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
pub struct Client<C> {
|
||||
pub network: network_defaults::all::Network,
|
||||
mixnet_contract_address: Option<cosmrs::AccountId>,
|
||||
vesting_contract_address: Option<cosmrs::AccountId>,
|
||||
erc20_bridge_contract_address: Option<cosmrs::AccountId>,
|
||||
mnemonic: Option<bip39::Mnemonic>,
|
||||
|
||||
mixnode_page_limit: Option<u32>,
|
||||
gateway_page_limit: Option<u32>,
|
||||
mixnode_delegations_page_limit: Option<u32>,
|
||||
rewarded_set_page_limit: Option<u32>,
|
||||
|
||||
// ideally they would have been read-only, but unfortunately rust doesn't have such features
|
||||
pub validator_api: validator_api::Client,
|
||||
@@ -90,20 +116,25 @@ impl Client<SigningNymdClient> {
|
||||
) -> Result<Client<SigningNymdClient>, ValidatorClientError> {
|
||||
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
||||
let nymd_client = NymdClient::connect_with_mnemonic(
|
||||
config.network,
|
||||
config.nymd_url.as_str(),
|
||||
config.mixnet_contract_address.clone(),
|
||||
config.vesting_contract_address.clone(),
|
||||
config.erc20_bridge_contract_address.clone(),
|
||||
mnemonic.clone(),
|
||||
None,
|
||||
)?;
|
||||
|
||||
Ok(Client {
|
||||
network: config.network,
|
||||
mixnet_contract_address: config.mixnet_contract_address,
|
||||
vesting_contract_address: config.vesting_contract_address,
|
||||
erc20_bridge_contract_address: config.erc20_bridge_contract_address,
|
||||
mnemonic: Some(mnemonic),
|
||||
mixnode_page_limit: config.mixnode_page_limit,
|
||||
gateway_page_limit: config.gateway_page_limit,
|
||||
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
|
||||
rewarded_set_page_limit: None,
|
||||
validator_api: validator_api_client,
|
||||
nymd: nymd_client,
|
||||
})
|
||||
@@ -111,9 +142,11 @@ impl Client<SigningNymdClient> {
|
||||
|
||||
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
|
||||
self.nymd = NymdClient::connect_with_mnemonic(
|
||||
self.network,
|
||||
new_endpoint.as_ref(),
|
||||
self.mixnet_contract_address.clone(),
|
||||
self.vesting_contract_address.clone(),
|
||||
self.erc20_bridge_contract_address.clone(),
|
||||
self.mnemonic.clone().unwrap(),
|
||||
None,
|
||||
)?;
|
||||
@@ -127,23 +160,35 @@ impl Client<QueryNymdClient> {
|
||||
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
||||
let nymd_client = NymdClient::connect(
|
||||
config.nymd_url.as_str(),
|
||||
config.mixnet_contract_address.clone().unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(network_defaults::DEFAULT_MIXNET_CONTRACT_ADDRESS)
|
||||
.unwrap()
|
||||
}),
|
||||
config.vesting_contract_address.clone().unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(network_defaults::DEFAULT_VESTING_CONTRACT_ADDRESS)
|
||||
.unwrap()
|
||||
}),
|
||||
Some(config.mixnet_contract_address.clone().unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(DEFAULT_NETWORK.mixnet_contract_address()).unwrap()
|
||||
})),
|
||||
Some(config.vesting_contract_address.clone().unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(DEFAULT_NETWORK.vesting_contract_address()).unwrap()
|
||||
})),
|
||||
Some(
|
||||
config
|
||||
.erc20_bridge_contract_address
|
||||
.clone()
|
||||
.unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(
|
||||
DEFAULT_NETWORK.bandwidth_claim_contract_address(),
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
),
|
||||
)?;
|
||||
|
||||
Ok(Client {
|
||||
network: config.network,
|
||||
mixnet_contract_address: config.mixnet_contract_address,
|
||||
vesting_contract_address: config.vesting_contract_address,
|
||||
erc20_bridge_contract_address: config.erc20_bridge_contract_address,
|
||||
mnemonic: None,
|
||||
mixnode_page_limit: config.mixnode_page_limit,
|
||||
gateway_page_limit: config.gateway_page_limit,
|
||||
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
|
||||
rewarded_set_page_limit: config.rewarded_set_page_limit,
|
||||
validator_api: validator_api_client,
|
||||
nymd: nymd_client,
|
||||
})
|
||||
@@ -152,8 +197,9 @@ impl Client<QueryNymdClient> {
|
||||
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
|
||||
self.nymd = NymdClient::connect(
|
||||
new_endpoint.as_ref(),
|
||||
self.mixnet_contract_address.clone().unwrap(),
|
||||
self.vesting_contract_address.clone().unwrap(),
|
||||
self.mixnet_contract_address.clone(),
|
||||
self.vesting_contract_address.clone(),
|
||||
self.erc20_bridge_contract_address.clone(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -179,6 +225,18 @@ impl<C> Client<C> {
|
||||
Ok(self.validator_api.get_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_rewarded_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_rewarded_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_active_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_active_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_gateways().await?)
|
||||
}
|
||||
@@ -190,25 +248,45 @@ impl<C> Client<C> {
|
||||
Ok(self.nymd.get_contract_settings().await?)
|
||||
}
|
||||
|
||||
pub async fn get_operator_rewards(&self, address: String) -> Result<u128, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.nymd.get_operator_rewards(address).await?.u128())
|
||||
}
|
||||
|
||||
pub async fn get_delegator_rewards(
|
||||
&self,
|
||||
address: String,
|
||||
mix_identity: IdentityKey,
|
||||
) -> Result<u128, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self
|
||||
.nymd
|
||||
.get_delegator_rewards(address, mix_identity)
|
||||
.await?
|
||||
.u128())
|
||||
}
|
||||
|
||||
pub async fn get_current_epoch(&self) -> Result<Option<Interval>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.nymd.get_current_epoch().await?)
|
||||
}
|
||||
|
||||
pub async fn get_mixnet_contract_version(&self) -> Result<MixnetContractVersion, NymdError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.nymd.get_mixnet_contract_version().await?)
|
||||
}
|
||||
|
||||
pub async fn get_current_rewarding_interval(
|
||||
&self,
|
||||
) -> Result<RewardingIntervalResponse, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.nymd.get_current_rewarding_interval().await?)
|
||||
self.nymd.get_mixnet_contract_version().await
|
||||
}
|
||||
|
||||
pub async fn get_rewarding_status(
|
||||
&self,
|
||||
mix_identity: mixnet_contract::IdentityKey,
|
||||
mix_identity: mixnet_contract_common::IdentityKey,
|
||||
rewarding_interval_nonce: u32,
|
||||
) -> Result<MixnodeRewardingStatusResponse, ValidatorClientError>
|
||||
where
|
||||
@@ -241,14 +319,143 @@ impl<C> Client<C> {
|
||||
Ok(self.nymd.get_sybil_resistance_percent().await?)
|
||||
}
|
||||
|
||||
pub async fn get_epoch_reward_percent(&self) -> Result<u8, ValidatorClientError>
|
||||
pub async fn get_active_set_work_factor(&self) -> Result<u8, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.nymd.get_epoch_reward_percent().await?)
|
||||
Ok(self.nymd.get_active_set_work_factor().await?)
|
||||
}
|
||||
|
||||
pub async fn get_epochs_in_interval(&self) -> Result<u64, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.nymd.get_epochs_in_interval().await?)
|
||||
}
|
||||
|
||||
pub async fn get_interval_reward_percent(&self) -> Result<u8, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.nymd.get_interval_reward_percent().await?)
|
||||
}
|
||||
|
||||
pub async fn get_current_rewarded_set_update_details(
|
||||
&self,
|
||||
) -> Result<RewardedSetUpdateDetails, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self
|
||||
.nymd
|
||||
.query_current_rewarded_set_update_details()
|
||||
.await?)
|
||||
}
|
||||
|
||||
// basically handles paging for us
|
||||
pub async fn get_all_nymd_rewarded_set_mixnode_identities(
|
||||
&self,
|
||||
) -> Result<Vec<(IdentityKey, RewardedSetNodeStatus)>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
let mut identities = Vec::new();
|
||||
let mut start_after = None;
|
||||
let mut height = None;
|
||||
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nymd
|
||||
.get_rewarded_set_identities_paged(
|
||||
start_after.take(),
|
||||
self.rewarded_set_page_limit,
|
||||
height,
|
||||
)
|
||||
.await?;
|
||||
identities.append(&mut paged_response.identities);
|
||||
|
||||
if height.is_none() {
|
||||
// keep using the same height (the first query happened at the most recent height)
|
||||
height = Some(paged_response.at_height)
|
||||
}
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(identities)
|
||||
}
|
||||
|
||||
pub async fn get_nymd_rewarded_and_active_sets(
|
||||
&self,
|
||||
) -> Result<Vec<(MixNodeBond, RewardedSetNodeStatus)>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
let all_mixnodes = self.get_all_nymd_mixnodes().await?;
|
||||
let rewarded_set_identities = self
|
||||
.get_all_nymd_rewarded_set_mixnode_identities()
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
Ok(all_mixnodes
|
||||
.into_iter()
|
||||
.filter_map(|node| {
|
||||
rewarded_set_identities
|
||||
.get(node.identity())
|
||||
.map(|status| (node, *status))
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// If you need both rewarded and the active set, consider using [Self::get_nymd_rewarded_and_active_sets] instead
|
||||
pub async fn get_nymd_rewarded_set(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
let all_mixnodes = self.get_all_nymd_mixnodes().await?;
|
||||
let rewarded_set_identities = self
|
||||
.get_all_nymd_rewarded_set_mixnode_identities()
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|(identity, _status)| identity)
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
Ok(all_mixnodes
|
||||
.into_iter()
|
||||
.filter(|node| rewarded_set_identities.contains(node.identity()))
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// If you need both rewarded and the active set, consider using [Self::get_nymd_rewarded_and_active_sets] instead
|
||||
pub async fn get_nymd_active_set(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
let all_mixnodes = self.get_all_nymd_mixnodes().await?;
|
||||
let active_set_identities = self
|
||||
.get_all_nymd_rewarded_set_mixnode_identities()
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter_map(|(identity, status)| {
|
||||
if status.is_active() {
|
||||
Some(identity)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
Ok(all_mixnodes
|
||||
.into_iter()
|
||||
.filter(|node| active_set_identities.contains(node.identity()))
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn get_all_nymd_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
@@ -297,8 +504,8 @@ impl<C> Client<C> {
|
||||
|
||||
pub async fn get_all_nymd_single_mixnode_delegations(
|
||||
&self,
|
||||
identity: mixnet_contract::IdentityKey,
|
||||
) -> Result<Vec<mixnet_contract::Delegation>, ValidatorClientError>
|
||||
identity: IdentityKey,
|
||||
) -> Result<Vec<Delegation>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
@@ -420,6 +627,12 @@ impl ApiClient {
|
||||
Ok(self.validator_api.get_active_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_rewarded_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_rewarded_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_mixnodes().await?)
|
||||
}
|
||||
@@ -428,6 +641,55 @@ impl ApiClient {
|
||||
Ok(self.validator_api.get_gateways().await?)
|
||||
}
|
||||
|
||||
pub async fn get_gateway_core_status_count(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
since: Option<i64>,
|
||||
) -> Result<CoreNodeStatusResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.validator_api
|
||||
.get_gateway_core_status_count(identity, since)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_core_status_count(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
since: Option<i64>,
|
||||
) -> Result<CoreNodeStatusResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.validator_api
|
||||
.get_mixnode_core_status_count(identity, since)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_status(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Result<MixnodeStatusResponse, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_mixnode_status(identity).await?)
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_reward_estimation(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Result<RewardEstimationResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.validator_api
|
||||
.get_mixnode_reward_estimation(identity)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_stake_saturation(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Result<StakeSaturationResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.validator_api
|
||||
.get_mixnode_stake_saturation(identity)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn blind_sign(
|
||||
&self,
|
||||
request_body: &BlindSignRequestBody,
|
||||
|
||||
@@ -9,6 +9,7 @@ pub mod validator_api;
|
||||
|
||||
pub use crate::client::ApiClient;
|
||||
pub use crate::error::ValidatorClientError;
|
||||
pub use validator_api_requests::*;
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
pub use client::{Client, Config};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nymd::cosmwasm_client::helpers::create_pagination;
|
||||
use crate::nymd::cosmwasm_client::helpers::{create_pagination, next_page_key};
|
||||
use crate::nymd::cosmwasm_client::types::{
|
||||
Account, Code, CodeDetails, Contract, ContractCodeHistoryEntry, ContractCodeId,
|
||||
SequenceResponse, SimulateResponse,
|
||||
@@ -13,6 +13,7 @@ use cosmrs::proto::cosmos::auth::v1beta1::{
|
||||
};
|
||||
use cosmrs::proto::cosmos::bank::v1beta1::{
|
||||
QueryAllBalancesRequest, QueryAllBalancesResponse, QueryBalanceRequest, QueryBalanceResponse,
|
||||
QueryTotalSupplyRequest, QueryTotalSupplyResponse,
|
||||
};
|
||||
use cosmrs::proto::cosmos::tx::v1beta1::{
|
||||
SimulateRequest, SimulateResponse as ProtoSimulateResponse,
|
||||
@@ -27,6 +28,7 @@ use cosmrs::tendermint::abci::Code as AbciCode;
|
||||
use cosmrs::tendermint::abci::Transaction;
|
||||
use cosmrs::tendermint::{abci, block, chain};
|
||||
use cosmrs::{tx, AccountId, Coin, Denom, Tx};
|
||||
use cosmwasm_std::Coin as CosmWasmCoin;
|
||||
use prost::Message;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
@@ -148,8 +150,8 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
.await?;
|
||||
|
||||
raw_balances.append(&mut res.balances);
|
||||
if let Some(pagination_info) = res.pagination {
|
||||
pagination = Some(create_pagination(pagination_info.next_key))
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -162,6 +164,43 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
.map_err(|_| NymdError::SerializationError("Coins".to_owned()))
|
||||
}
|
||||
|
||||
// this is annoyingly and inconsistently returning `Vec<CosmWasmCoin>` rather than
|
||||
// Vec<Coin>, since cosmrs::Coin can't deal with IBC denoms.
|
||||
// Presumably after https://github.com/cosmos/cosmos-rust/issues/173 is resolved,
|
||||
// the code could be adjusted
|
||||
async fn get_total_supply(&self) -> Result<Vec<CosmWasmCoin>, NymdError> {
|
||||
let path = Some("/cosmos.bank.v1beta1.Query/TotalSupply".parse().unwrap());
|
||||
|
||||
let mut supply = Vec::new();
|
||||
let mut pagination = None;
|
||||
|
||||
loop {
|
||||
let req = QueryTotalSupplyRequest { pagination };
|
||||
|
||||
let mut res = self
|
||||
.make_abci_query::<_, QueryTotalSupplyResponse>(path.clone(), req)
|
||||
.await?;
|
||||
|
||||
supply.append(&mut res.supply);
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
supply
|
||||
.into_iter()
|
||||
.map(|coin| {
|
||||
coin.amount.parse().map(|amount| CosmWasmCoin {
|
||||
denom: coin.denom,
|
||||
amount,
|
||||
})
|
||||
})
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(|_| NymdError::SerializationError("Coins".to_owned()))
|
||||
}
|
||||
|
||||
async fn get_tx(&self, id: tx::Hash) -> Result<TxResponse, NymdError> {
|
||||
Ok(self.tx(id, false).await?)
|
||||
}
|
||||
@@ -235,8 +274,8 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
.await?;
|
||||
|
||||
raw_codes.append(&mut res.code_infos);
|
||||
if let Some(pagination_info) = res.pagination {
|
||||
pagination = Some(create_pagination(pagination_info.next_key))
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -280,8 +319,8 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
.await?;
|
||||
|
||||
raw_contracts.append(&mut res.contracts);
|
||||
if let Some(pagination_info) = res.pagination {
|
||||
pagination = Some(create_pagination(pagination_info.next_key))
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -336,8 +375,8 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
.await?;
|
||||
|
||||
raw_entries.append(&mut res.entries);
|
||||
if let Some(pagination_info) = res.pagination {
|
||||
pagination = Some(create_pagination(pagination_info.next_key))
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||