Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aa6c555821 | |||
| 2f5441c6e3 |
+2
-2
@@ -15,8 +15,8 @@
|
||||
* @futurechimp @mmsinclair
|
||||
|
||||
# Rust rules:
|
||||
*.rs @durch @futurechimp @jstuczyn @neacsu @octol
|
||||
Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol
|
||||
*.rs @durch @futurechimp @jstuczyn @neacsu
|
||||
Cargo.* @durch @futurechimp @jstuczyn @neacsu
|
||||
|
||||
# JS rules:
|
||||
*.js @mmsinclair @fmtabbara @Aid19801
|
||||
|
||||
@@ -9,14 +9,28 @@ 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:
|
||||
runs-on: [ self-hosted, custom-linux-exoscale ]
|
||||
# Enable sccache via environment variable
|
||||
env:
|
||||
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
||||
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' }}
|
||||
steps:
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||
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
|
||||
@@ -25,7 +39,7 @@ jobs:
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
@@ -49,16 +63,25 @@ 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
|
||||
|
||||
- name: Build all binaries with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
@@ -73,6 +96,7 @@ jobs:
|
||||
|
||||
- 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,10 +10,41 @@
|
||||
"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"
|
||||
}
|
||||
]
|
||||
]
|
||||
@@ -41,10 +41,9 @@ jobs:
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Keybase - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
working-directory: .github/workflows/support-files/messages
|
||||
- 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 }}"
|
||||
@@ -57,4 +56,4 @@ jobs:
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
args: .github/workflows/support-files/messages/entry_point_notifications.sh
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
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: --all
|
||||
|
||||
- name: Run all tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
name: Clippy checks
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
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
|
||||
|
||||
- name: Build all binaries with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --all --features=coconut
|
||||
|
||||
- name: Run all tests with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all --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
|
||||
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
|
||||
@@ -1,50 +0,0 @@
|
||||
[
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
@@ -1,77 +0,0 @@
|
||||
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
|
||||
@@ -1,46 +0,0 @@
|
||||
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
|
||||
@@ -0,0 +1,12 @@
|
||||
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!
|
||||
@@ -10,10 +10,7 @@ on:
|
||||
|
||||
jobs:
|
||||
nym-wallet-types:
|
||||
runs-on: [ self-hosted, custom-linux-exoscale ]
|
||||
# Enable sccache
|
||||
env:
|
||||
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
steps:
|
||||
- name: Prepare
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
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
|
||||
@@ -1,5 +0,0 @@
|
||||
node_modules
|
||||
.idea
|
||||
|
||||
# don't commit the lock file to avoid cross-platform issues
|
||||
package-lock.json
|
||||
@@ -1 +0,0 @@
|
||||
16
|
||||
@@ -1,58 +0,0 @@
|
||||
# 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
|
||||
```
|
||||
@@ -1 +0,0 @@
|
||||
require('./notifications/send_message');
|
||||
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
.idea
|
||||
+2
-5
@@ -4,14 +4,11 @@
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "node dev.js",
|
||||
"format": "prettier --write **/*.js"
|
||||
"format": "prettier --write send_message.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"keybase-bot": "^3.6.1",
|
||||
"octokit": "^1.7.1"
|
||||
"keybase-bot": "^3.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "2.3.2"
|
||||
@@ -0,0 +1,69 @@
|
||||
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();
|
||||
+1
-1
@@ -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 by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||
Commit message:
|
||||
```
|
||||
{{ env.GIT_COMMIT_MESSAGE }}
|
||||
```
|
||||
@@ -1,29 +0,0 @@
|
||||
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,
|
||||
};
|
||||
@@ -1,162 +0,0 @@
|
||||
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,
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :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 }}
|
||||
@@ -1,9 +0,0 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :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 }}
|
||||
@@ -1,153 +0,0 @@
|
||||
require('dotenv').config();
|
||||
|
||||
const Bot = require('keybase-bot');
|
||||
|
||||
let context = {
|
||||
kinds: ['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();
|
||||
@@ -19,27 +19,30 @@ jobs:
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
|
||||
# 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 --features=coconut
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --manifest-path clients/webassembly/Cargo.toml
|
||||
# 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: fmt
|
||||
args: --manifest-path clients/webassembly/Cargo.toml -- --check
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
|
||||
# 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
|
||||
|
||||
Generated
+192
-644
File diff suppressed because it is too large
Load Diff
+4
-6
@@ -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",
|
||||
"common/client-libs/gateway-client",
|
||||
"common/client-libs/mixnet-client",
|
||||
"common/client-libs/validator-client",
|
||||
@@ -26,9 +26,7 @@ members = [
|
||||
"common/credentials",
|
||||
"common/crypto",
|
||||
"common/bandwidth-claim-contract",
|
||||
"common/cosmwasm-smart-contracts/contracts-common",
|
||||
"common/cosmwasm-smart-contracts/mixnet-contract",
|
||||
"common/cosmwasm-smart-contracts/vesting-contract",
|
||||
"common/mixnet-contract",
|
||||
"common/mixnode-common",
|
||||
"common/network-defaults",
|
||||
"common/nonexhaustive-delayqueue",
|
||||
@@ -54,12 +52,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",
|
||||
@@ -67,4 +65,4 @@ default-members = [
|
||||
"explorer-api",
|
||||
]
|
||||
|
||||
exclude = ["explorer", "contracts", "tokenomics-py", "clients/webassembly"]
|
||||
exclude = ["explorer", "contracts", "tokenomics-py"]
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
test: build clippy-all cargo-test wasm fmt
|
||||
happy: fmt clippy-happy test
|
||||
all: clippy-all test fmt
|
||||
happy: clippy-happy test fmt
|
||||
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet
|
||||
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet
|
||||
cargo-test: test-main test-contracts test-wallet
|
||||
build: build-main build-contracts build-wallet
|
||||
test: test-main test-contracts test-wallet
|
||||
fmt: fmt-main fmt-contracts fmt-wallet
|
||||
|
||||
clippy-happy-main:
|
||||
@@ -33,15 +32,6 @@ test-contracts:
|
||||
test-wallet:
|
||||
cargo test --manifest-path nym-wallet/Cargo.toml --all-features
|
||||
|
||||
build-main:
|
||||
cargo build --all
|
||||
|
||||
build-contracts:
|
||||
cargo build --manifest-path contracts/Cargo.toml --all
|
||||
|
||||
build-wallet:
|
||||
cargo build --manifest-path nym-wallet/Cargo.toml --all
|
||||
|
||||
fmt-main:
|
||||
cargo fmt --all
|
||||
|
||||
|
||||
@@ -21,8 +21,7 @@ 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/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).
|
||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/0.11.0/overview/index/).
|
||||
|
||||
### Developing
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "client-core"
|
||||
version = "0.12.0"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
edition = "2018"
|
||||
|
||||
# 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())?;
|
||||
pemstore::load_key(&client_pathfinder.gateway_shared_key().to_owned())?;
|
||||
|
||||
let ack_key: AckKey = pemstore::load_key(client_pathfinder.ack_key())?;
|
||||
let ack_key: AckKey = pemstore::load_key(&client_pathfinder.ack_key().to_owned())?;
|
||||
|
||||
// TODO: ack key is never stored so it is generated now. But perhaps it should be stored
|
||||
// after all for consistency sake?
|
||||
|
||||
@@ -59,7 +59,7 @@ impl ReplyKeyStorage {
|
||||
) -> Result<(), ReplyKeyStorageError> {
|
||||
let digest = encryption_key.compute_digest();
|
||||
|
||||
let insertion_result = match self.db.insert(digest, encryption_key.to_bytes()) {
|
||||
let insertion_result = match self.db.insert(digest.to_vec(), 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) {
|
||||
let removal_result = match self.db.remove(&key_digest.to_vec()) {
|
||||
Err(e) => Err(ReplyKeyStorageError::DbReadError(e)),
|
||||
Ok(existing_key) => {
|
||||
Ok(existing_key.map(|existing_key| self.read_encryption_key(existing_key)))
|
||||
|
||||
@@ -121,16 +121,12 @@ impl<T: NymConfig> Config<T> {
|
||||
self.client.testnet_mode = testnet_mode;
|
||||
}
|
||||
|
||||
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_id<S: Into<String>>(&mut self, id: S) {
|
||||
self.client.gateway_id = id.into();
|
||||
}
|
||||
|
||||
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
||||
self.client.gateway_endpoint.gateway_id = id.into();
|
||||
pub fn with_gateway_listener<S: Into<String>>(&mut self, gateway_listener: S) {
|
||||
self.client.gateway_listener = gateway_listener.into();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
@@ -202,15 +198,11 @@ impl<T: NymConfig> Config<T> {
|
||||
}
|
||||
|
||||
pub fn get_gateway_id(&self) -> String {
|
||||
self.client.gateway_endpoint.gateway_id.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_owner(&self) -> String {
|
||||
self.client.gateway_endpoint.gateway_owner.clone()
|
||||
self.client.gateway_id.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_listener(&self) -> String {
|
||||
self.client.gateway_endpoint.gateway_listener.clone()
|
||||
self.client.gateway_listener.clone()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
@@ -280,19 +272,6 @@ 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.
|
||||
@@ -334,8 +313,12 @@ pub struct Client<T> {
|
||||
/// sent but not received back.
|
||||
reply_encryption_key_store_path: PathBuf,
|
||||
|
||||
/// Information regarding how the client should send data to gateway.
|
||||
gateway_endpoint: 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 listener to which all client requests should be sent.
|
||||
gateway_listener: String,
|
||||
|
||||
/// 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.
|
||||
@@ -374,7 +357,8 @@ 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_endpoint: Default::default(),
|
||||
gateway_id: "".to_string(),
|
||||
gateway_listener: "".to_string(),
|
||||
#[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 = "2021"
|
||||
edition = "2018"
|
||||
rust-version = "1.56"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# Nym Desktop Client
|
||||
|
||||
The Nym Desktop Client communicates with the remote, decentralised nodes which make up the Nym system as a whole.
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# Nym Desktop Client Code Examples
|
||||
|
||||
This directory contains example code for javascript, python, and rust. Please note that **none of these examples are production-ready**, and are included really just to show how the client interacts with the Nym system.
|
||||
|
||||
> Make sure that you have an instance of the `nym-client` set up and running locally on port 1977 before trying to run any of these examples.
|
||||
|
||||
## Go
|
||||
There are two examples here:
|
||||
* `binarysend`, which (as the name suggests) sends a binary file, and
|
||||
* `textsend` which sends a raw text file.
|
||||
|
||||
Both examples send these files over the Nym mixnet to the address of your running Nym client, logging information in your terminal window.
|
||||
|
||||
## Javascript
|
||||
The example included here starts a websocket server on port 8888, the ui of which can be used to send strings over the Nym mixnet to the address of your running Nym client.
|
||||
|
||||
### Prerequisites
|
||||
* Reasonably up to date `NodeJS` & `npm` (>= ~v12)
|
||||
|
||||
### Running it
|
||||
Run the following commands:
|
||||
|
||||
```
|
||||
# install dependencies
|
||||
npm install
|
||||
# start a webserver on port 8888
|
||||
npm start
|
||||
```
|
||||
|
||||
Then open your browser to `localhost:8888`.
|
||||
|
||||
## Python
|
||||
There are two examples here:
|
||||
* `binarysend`, which (as the name suggests) sends a binary file, and
|
||||
* `textsend` which sends a raw text file.
|
||||
|
||||
Both examples send these files over the Nym mixnet to the address of your running Nym client, logging information in your terminal window.
|
||||
|
||||
Make sure that you have an instance of the `nym-client` set up and running locally on port 1977 before trying to run either of the example scripts.
|
||||
|
||||
## Rust
|
||||
There are two examples here:
|
||||
* `binarysend`, which (as the name suggests) sends a binary file, and
|
||||
* `textsend` which sends a raw text file.
|
||||
|
||||
Both examples send these files over the Nym mixnet to the address of your running Nym client, logging information in your terminal window.
|
||||
|
||||
Make sure that you have an instance of the `nym-client` set up and running locally on port 1977 before trying to run either of the example scripts.
|
||||
Binary file not shown.
@@ -1,10 +0,0 @@
|
||||
### Prerequisites
|
||||
|
||||
* Reasonably up to date Node + `npm`
|
||||
|
||||
### Running it
|
||||
|
||||
```
|
||||
npm install
|
||||
npm start # starts a webserver on port 8888
|
||||
```
|
||||
+513
-6996
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.5",
|
||||
"html-webpack-plugin": "^4.2.0"
|
||||
"html-webpack-plugin": "^4.2.0",
|
||||
"postcss": "^8.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis efficitur neque. Quisque aliquet vulputate ante, eget vehicula odio feugiat ac. Nulla ut mattis magna. Aenean tincidunt quis nulla eget eleifend. Cras in pretium sem. Nunc lorem metus, blandit sit amet egestas ut, feugiat quis tellus. Aenean tristique, enim a tincidunt condimentum, eros est blandit nunc, id viverra metus erat at nulla. Vivamus at tellus sodales, feugiat odio vel, laoreet neque. Vivamus posuere nulla ac sodales bibendum.
|
||||
|
||||
Vestibulum pulvinar nisi non ultricies egestas. Integer finibus ultrices justo vitae suscipit. Etiam interdum eu justo vel interdum. Morbi sagittis ac nisl quis consequat. Mauris dapibus ut risus ac facilisis. Pellentesque non tortor feugiat, consectetur arcu vel, ullamcorper sapien. Proin sodales purus non orci bibendum, sit amet ultrices justo ullamcorper. Nullam ac risus ac justo ultricies efficitur auctor nec arcu. Etiam sed finibus felis. Suspendisse potenti. Phasellus malesuada velit ac ullamcorper egestas. Sed elementum diam ut est gravida ultricies.
|
||||
|
||||
Pellentesque sed metus massa. Cras imperdiet lacus sit amet dolor aliquam, luctus posuere justo hendrerit. Morbi augue ex, gravida a metus sed, scelerisque euismod lacus. Nam consequat sapien ac pellentesque sagittis. Morbi a ultrices massa, vel aliquet ex. Maecenas ac sem diam. Nunc sed erat et ipsum volutpat auctor. Etiam elit felis, commodo vitae ipsum ac, fermentum lobortis arcu. Aliquam eu tempus enim. Curabitur vulputate imperdiet aliquam. Morbi iaculis rhoncus risus at malesuada. Donec accumsan feugiat ligula ut facilisis. Nunc porttitor sit amet est eget malesuada. Sed sed consectetur augue, non dapibus orci. Mauris aliquam pellentesque quam, sit amet pellentesque velit cursus vitae. Morbi sit amet molestie risus.
|
||||
|
||||
Nam gravida non ligula a egestas. Fusce sodales, purus id rhoncus mattis, purus est vehicula urna, vel finibus augue velit et est. Donec dictum erat eleifend lobortis iaculis. Praesent id venenatis ante. Donec feugiat, ipsum eget porttitor pulvinar, nisl odio posuere lorem, ut placerat elit nulla a ligula. Suspendisse nec nibh tincidunt, sollicitudin mi a, volutpat ligula. In maximus quam lacus, eget semper dolor sagittis sit amet.
|
||||
|
||||
In vitae hendrerit est, quis facilisis dui. In eu ante enim. Nullam hendrerit odio sit amet odio tincidunt eleifend. Aliquam erat volutpat. Curabitur commodo, purus pharetra lobortis rhoncus, tortor massa imperdiet nisl, vel dignissim tortor sem at orci. Aliquam maximus lobortis lacus, eu porttitor purus dapibus ut. Praesent at dapibus felis, efficitur blandit tortor. In hac habitasse platea dictumst. Aenean ultrices, nisl a pretium sagittis, tellus sapien mollis erat, eu consectetur erat mauris sed libero. Duis feugiat dapibus mi, vel ornare velit vehicula mattis. Ut suscipit pharetra leo et sollicitudin.
|
||||
+2
-2
@@ -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);
|
||||
println!("our full address is: {}", recipient.to_string());
|
||||
|
||||
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);
|
||||
println!("our full address is: {}", recipient.to_string());
|
||||
|
||||
let read_data = std::fs::read("examples/dummy_file").unwrap();
|
||||
|
||||
+2
-2
@@ -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);
|
||||
println!("our full address is: {}", recipient.to_string());
|
||||
|
||||
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);
|
||||
println!("our full address is: {}", recipient.to_string());
|
||||
|
||||
let send_request = json!({
|
||||
"type" : "send",
|
||||
@@ -59,6 +59,12 @@ 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,17 +78,6 @@ 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,10 +160,6 @@ 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?")
|
||||
@@ -189,7 +185,6 @@ 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,7 +136,6 @@ 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,14 +255,15 @@ 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_endpoint(
|
||||
gateway_details.identity_key.to_base58_string(),
|
||||
gateway_details.owner.clone(),
|
||||
gateway_details.clients_address(),
|
||||
);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(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<'_>) -> C
|
||||
#[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 if !cfg!(feature = "eth") {
|
||||
} else {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
||||
@@ -66,7 +66,7 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> C
|
||||
#[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 if !cfg!(feature = "eth") {
|
||||
} else {
|
||||
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: Ver
|
||||
}
|
||||
}
|
||||
|
||||
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 = "2021"
|
||||
edition = "2018"
|
||||
|
||||
# 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 = "2021"
|
||||
edition = "2018"
|
||||
rust-version = "1.56"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -59,6 +59,12 @@ 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 }}'
|
||||
@@ -66,22 +72,12 @@ 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,10 +148,6 @@ 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?")
|
||||
@@ -177,7 +173,6 @@ 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,7 +136,6 @@ 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,
|
||||
);
|
||||
@@ -257,14 +256,15 @@ 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_endpoint(
|
||||
gateway_details.identity_key.to_base58_string(),
|
||||
gateway_details.owner.clone(),
|
||||
gateway_details.clients_address(),
|
||||
);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(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<'_>) -> C
|
||||
#[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 if !cfg!(feature = "eth") {
|
||||
} else {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
||||
@@ -62,7 +62,7 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> C
|
||||
#[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 if !cfg!(feature = "eth") {
|
||||
} else {
|
||||
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: Ver
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches<'_>) {
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
let package_version = parse_package_version();
|
||||
|
||||
let id = matches.value_of("id").unwrap();
|
||||
|
||||
Generated
+7
-17
@@ -11,7 +11,6 @@
|
||||
"@tauri-apps/api": "^1.0.0-beta.4",
|
||||
"compression": "^1.7.1",
|
||||
"polka": "next",
|
||||
"qrious": "^4.0.2",
|
||||
"sirv": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -6759,11 +6758,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/qrious": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/qrious/-/qrious-4.0.2.tgz",
|
||||
"integrity": "sha512-xWPJIrK1zu5Ypn898fBp8RHkT/9ibquV2Kv24S/JY9VYEhMBMKur1gHVsOiNUh7PHP9uCgejjpZUHUIXXKoU/g=="
|
||||
},
|
||||
"node_modules/query-string": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
|
||||
@@ -7585,10 +7579,11 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/simple-get": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
|
||||
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
|
||||
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"decompress-response": "^4.2.0",
|
||||
"once": "^1.3.1",
|
||||
@@ -13479,11 +13474,6 @@
|
||||
"escape-goat": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"qrious": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/qrious/-/qrious-4.0.2.tgz",
|
||||
"integrity": "sha512-xWPJIrK1zu5Ypn898fBp8RHkT/9ibquV2Kv24S/JY9VYEhMBMKur1gHVsOiNUh7PHP9uCgejjpZUHUIXXKoU/g=="
|
||||
},
|
||||
"query-string": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
|
||||
@@ -14046,9 +14036,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"simple-get": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
|
||||
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
|
||||
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"decompress-response": "^4.2.0",
|
||||
|
||||
@@ -6,7 +6,7 @@ authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
default-run = "app"
|
||||
edition = "2021"
|
||||
edition = "2018"
|
||||
build = "src/build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -1813,7 +1813,7 @@ decompress-response@^3.2.0, decompress-response@^3.3.0:
|
||||
|
||||
decompress-response@^4.2.0:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986"
|
||||
resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz"
|
||||
integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==
|
||||
dependencies:
|
||||
mimic-response "^2.0.0"
|
||||
@@ -3130,7 +3130,7 @@ mimic-response@^1.0.0, mimic-response@^1.0.1:
|
||||
|
||||
mimic-response@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
|
||||
resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz"
|
||||
integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
|
||||
|
||||
mimic-response@^3.1.0:
|
||||
@@ -4056,13 +4056,13 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
|
||||
|
||||
simple-concat@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f"
|
||||
resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz"
|
||||
integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==
|
||||
|
||||
simple-get@^3.0.3, simple-get@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.1.tgz#cc7ba77cfbe761036fbfce3d021af25fc5584d55"
|
||||
integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz"
|
||||
integrity sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==
|
||||
dependencies:
|
||||
decompress-response "^4.2.0"
|
||||
once "^1.3.1"
|
||||
@@ -4673,7 +4673,7 @@ wrap-ansi@^7.0.0:
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
write-file-atomic@^3.0.0:
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
# CLIENT INIT
|
||||
NYMD_URL=https://sandbox-validator.nymtech.net
|
||||
VALIDATOR_API=https://sandbox-validator.nymtech.net/api
|
||||
MIXNET_CONTRACT=nymt1ghd753shjuwexxywmgs4xz7x2q732vcnstz02j
|
||||
VESTING_CONTRACT=nymt1nc5tatafv6eyq7llkr2gv50ff9e22mnfp9pc5s
|
||||
CURRENCY_PREFIX=nymt
|
||||
CHAIN_ID=nym-sandbox
|
||||
|
||||
# USER DETAILS
|
||||
USER_MNEMONIC=
|
||||
USER_WALLET_ADDRESS=
|
||||
|
||||
# MIXNODE DETAILS
|
||||
MIXNODE_IDENTITY=
|
||||
MIXNODE_SPHINX_KEY=
|
||||
MIXNODE_SIGNATURE=
|
||||
MIXNODE_HOST="1.1.1.1"
|
||||
MIXNODE_VERSION="0.12.1"
|
||||
|
||||
# GATEWAY DETAILS
|
||||
GATEWAY_IDENTITY=
|
||||
GATEWAY_SPHINX=
|
||||
GATEAWAY_LOCATION=
|
||||
GATEWAY_HOST="1.1.1.1"
|
||||
GATEWAY_VERSION="0.12.1"
|
||||
@@ -3,20 +3,26 @@ Nym Validator Client
|
||||
|
||||
A TypeScript client for interacting with CosmWasm smart contracts in Nym validators.
|
||||
|
||||
Running examples
|
||||
-----------------
|
||||
|
||||
With the code checked out, `cd examples`. This folder contains runnable example code that will set up a blockchain and allow you to interact with it through the client.
|
||||
|
||||
Running tests
|
||||
-------------
|
||||
|
||||
The tests will be separated into three categories: unit, integration and mock.
|
||||
|
||||
Currently the command to run all tests:
|
||||
|
||||
```
|
||||
npm test
|
||||
```
|
||||
|
||||
The tests require `.env.example` being renamed to `.env`. The variables and their values for these tests are currently pointing to the `nym-sandbox` environment.
|
||||
You can also trigger test execution with a test watcher. I don't have the centuries of life left to me that are needed to fight through the arcana of wiring up a working TypeScript mocha triggered execution setup, so for now my Cargo-based hack is:
|
||||
|
||||
`Tests are still in development` - the test libary is `jest` and the test script will execute currently with: `--coverage --verbosity false`
|
||||
|
||||
```
|
||||
cargo watch -s "cd clients/validator && npm test"
|
||||
```
|
||||
|
||||
It's ugly but works fine if you have Cargo installed. TypeScript setup help happily accepted here.
|
||||
|
||||
Generating Documentation
|
||||
------------------------
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
|
||||
setupFiles: ["dotenv/config"],
|
||||
testTimeout: 20000
|
||||
};
|
||||
@@ -6,7 +6,9 @@
|
||||
"main": "./dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"test": "jest --verbose false",
|
||||
"build": "tsc",
|
||||
"test": "ts-mocha tests/**/*.test.ts",
|
||||
"coverage": "nyc npm test",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"docs": "typedoc --out docs src/index.ts"
|
||||
@@ -19,21 +21,27 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.4.0",
|
||||
"@types/chai": "^4.2.15",
|
||||
"@types/expect": "^24.3.0",
|
||||
"@types/mocha": "^8.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
||||
"@typescript-eslint/parser": "^5.7.0",
|
||||
"chai": "^4.2.0",
|
||||
"eslint": "^7.18.0",
|
||||
"eslint-config-airbnb": "^19.0.2",
|
||||
"eslint-config-airbnb-typescript": "^16.1.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-import-resolver-root-import": "^1.0.4",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-mocha": "^10.0.3",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^27.4.5",
|
||||
"mocha": "^8.2.1",
|
||||
"moq.ts": "^7.2.0",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^2.5.1",
|
||||
"ts-jest": "^27.1.2",
|
||||
"ts-mocha": "^8.0.0",
|
||||
"typedoc": "^0.20.27",
|
||||
"typescript": "^4.5.4"
|
||||
"typescript": "^4.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cosmjs/cosmwasm-stargate": "^0.27.0-rc2",
|
||||
@@ -43,8 +51,6 @@
|
||||
"@cosmjs/stargate": "^0.27.0-rc2",
|
||||
"@cosmjs/tendermint-rpc": "^0.27.0-rc2",
|
||||
"axios": "^0.21.1",
|
||||
"cosmjs-types": "^0.4.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"moq.ts": "^7.3.4"
|
||||
"cosmjs-types": "^0.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,8 +180,8 @@ export default class ValidatorClient implements INymClient {
|
||||
return this.client.getSybilResistancePercent(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getIntervalRewardPercent(): Promise<number> {
|
||||
return this.client.getIntervalRewardPercent(this.mixnetContract);
|
||||
public async getEpochRewardPercent(): Promise<number> {
|
||||
return this.client.getEpochRewardPercent(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getAllNymdMixnodes(): Promise<MixNodeBond[]> {
|
||||
@@ -433,14 +433,6 @@ 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,
|
||||
@@ -449,4 +441,4 @@ export default class ValidatorClient implements INymClient {
|
||||
this.assertSigning();
|
||||
return (this.client as ISigningClient).updateContractStateParams(this.mixnetContract, newParams, fee, memo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
RewardingIntervalResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
|
||||
@@ -78,6 +79,12 @@ export default class NymdQuerier implements INymdQuery {
|
||||
});
|
||||
}
|
||||
|
||||
getCurrentRewardingInterval(mixnetContractAddress: string): Promise<RewardingIntervalResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
current_rewarding_interval: {},
|
||||
});
|
||||
}
|
||||
|
||||
getAllNetworkDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
@@ -148,9 +155,9 @@ export default class NymdQuerier implements INymdQuery {
|
||||
});
|
||||
}
|
||||
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
getEpochRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_interval_reward_percent: {},
|
||||
get_epoch_reward_percent: {},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
RewardingIntervalResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
import ValidatorApiQuerier, { IValidatorApiQuery } from './validator-api-querier';
|
||||
@@ -62,6 +63,7 @@ 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,
|
||||
@@ -85,7 +87,7 @@ export interface INymdQuery {
|
||||
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution>;
|
||||
getRewardPool(mixnetContractAddress: string): Promise<string>;
|
||||
getCirculatingSupply(mixnetContractAddress: string): Promise<string>;
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number>;
|
||||
getEpochRewardPercent(mixnetContractAddress: string): Promise<number>;
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number>;
|
||||
getRewardingStatus(
|
||||
mixnetContractAddress: string,
|
||||
@@ -136,6 +138,10 @@ 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,
|
||||
@@ -178,8 +184,8 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
|
||||
return this.nymdQuerier.getCirculatingSupply(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nymdQuerier.getIntervalRewardPercent(mixnetContractAddress);
|
||||
getEpochRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nymdQuerier.getEpochRewardPercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
RewardingIntervalResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
import ValidatorApiQuerier from './validator-api-querier';
|
||||
@@ -177,13 +178,6 @@ 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,
|
||||
@@ -256,6 +250,10 @@ 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,
|
||||
@@ -298,8 +296,8 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
return this.nymdQuerier.getCirculatingSupply(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nymdQuerier.getIntervalRewardPercent(mixnetContractAddress);
|
||||
getEpochRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nymdQuerier.getEpochRewardPercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
|
||||
@@ -450,20 +448,6 @@ 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,19 +1,8 @@
|
||||
import axios from 'axios';
|
||||
import { GasPrice } from '@cosmjs/stargate';
|
||||
|
||||
const mainnetPrefix = 'n';
|
||||
const mainnetDenom = 'nym';
|
||||
|
||||
export function nymGasPrice(prefix: string): GasPrice {
|
||||
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`);
|
||||
}
|
||||
return GasPrice.fromString(`0.025u${prefix}`); // TODO: ideally this ugly conversion shouldn't be hardcoded here.
|
||||
}
|
||||
|
||||
export const downloadWasm = async (url: string): Promise<Uint8Array> => {
|
||||
|
||||
@@ -43,6 +43,12 @@ 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;
|
||||
@@ -129,7 +135,6 @@ export type MixNode = {
|
||||
sphinx_key: string;
|
||||
identity_key: string;
|
||||
version: string;
|
||||
profit_margin_percent: number;
|
||||
};
|
||||
|
||||
export type GatewayBond = {
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
import validator from "../../src/index";
|
||||
import { ExecuteResult } from "@cosmjs/cosmwasm-stargate";
|
||||
import { config } from "../test-utils/config";
|
||||
import {buildCoin, buildWallet, profitPercentage} from "../test-utils/utils"
|
||||
import {
|
||||
Gateway,
|
||||
GatewayOwnershipResponse,
|
||||
MixNode,
|
||||
MixOwnershipResponse,
|
||||
} from "../../src/types";
|
||||
|
||||
let response: ExecuteResult;
|
||||
let validatorClient: validator;
|
||||
let ownsMixNode: MixOwnershipResponse;
|
||||
let ownsGateway: GatewayOwnershipResponse;
|
||||
|
||||
beforeEach(async () => {
|
||||
validatorClient = await validator.connect(
|
||||
config.USER_MNEMONIC,
|
||||
config.NYMD_URL,
|
||||
config.VALIDATOR_API,
|
||||
config.NETWORK_BECH,
|
||||
config.MIXNET_CONTRACT,
|
||||
config.VESTING_CONTRACT
|
||||
);
|
||||
});
|
||||
|
||||
describe("long running e2e tests", () => {
|
||||
test.skip("token transfer", async () => {
|
||||
try {
|
||||
//make sure there's enough balance in the wallet
|
||||
|
||||
let coin = buildCoin("50000", "nymt");
|
||||
let userAddress = await buildWallet();
|
||||
let send = await validatorClient.send(
|
||||
userAddress,
|
||||
Array(coin),
|
||||
"auto",
|
||||
"send-tokens"
|
||||
);
|
||||
let jsonParse = JSON.parse(send.rawLog as string);
|
||||
|
||||
//check successful network broadcast - via events
|
||||
//1 - get key attributes values for sender an assert them
|
||||
//2 - get key attributes for receiver assert they match
|
||||
//3 - transaction hash present in response
|
||||
|
||||
// { array of events -> attribute -> event information }
|
||||
expect(jsonParse[0].events[1].attributes[1].value).toStrictEqual(
|
||||
config.USER_WALLET_ADDRESS
|
||||
);
|
||||
expect(jsonParse[0].events[1].attributes[0].value).toStrictEqual(
|
||||
userAddress
|
||||
);
|
||||
expect(jsonParse[0].events[1].type).toStrictEqual(
|
||||
"transfer"
|
||||
);
|
||||
expect(send.transactionHash).toStrictEqual(expect.any(String));
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
test.skip("update mixnode profit percentage", async () => {
|
||||
const nodeIdentity = config.MIXNODE_IDENTITY;
|
||||
const profitPercent = profitPercentage();
|
||||
|
||||
try {
|
||||
//use auto fees - simulated gas
|
||||
response = await validatorClient.updateMixnodeConfig(nodeIdentity, 'auto', profitPercent);
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
ownsMixNode = await validatorClient.client.ownsMixNode(config.MIXNET_CONTRACT, config.USER_WALLET_ADDRESS);
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
expect(ownsMixNode.mixnode?.mix_node.profit_margin_percent).toStrictEqual(profitPercent);
|
||||
});
|
||||
|
||||
test.skip("unbond and bond mixnode", async () => {
|
||||
|
||||
try {
|
||||
await validatorClient.unbondMixNode("auto", "unbond-mixnode");
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const profitPercent = profitPercentage();
|
||||
|
||||
const mixnodeDetails = <MixNode>{
|
||||
host: config.MIXNODE_HOST,
|
||||
mix_port: 1789,
|
||||
verloc_port: 1790,
|
||||
http_api_port: 8080,
|
||||
identity_key: config.MIXNODE_IDENTITY,
|
||||
sphinx_key: config.MIXNODE_SPHINX_KEY,
|
||||
version: config.MIXNODE_VERSION,
|
||||
profit_margin_percent: profitPercent
|
||||
};
|
||||
|
||||
const bond = buildCoin("100000000", config.CURRENCY_DENOM)
|
||||
|
||||
try {
|
||||
response = await validatorClient.bondMixNode(
|
||||
mixnodeDetails,
|
||||
config.MIXNODE_SIGNATURE,
|
||||
bond,
|
||||
"auto"
|
||||
);
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
ownsMixNode = await validatorClient.client.ownsMixNode(config.MIXNET_CONTRACT, config.USER_WALLET_ADDRESS);
|
||||
expect(ownsMixNode.mixnode?.mix_node.profit_margin_percent).toStrictEqual(profitPercent);
|
||||
});
|
||||
|
||||
test.skip("unbond and bond gateway", async () => {
|
||||
//gateway requires different user wallet
|
||||
//init inside test
|
||||
//todo
|
||||
|
||||
try {
|
||||
await validatorClient.unbondGateway("auto", "unbonding gateway");
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const gateway = <Gateway>{
|
||||
host: config.GATEWAY_HOST,
|
||||
mix_port: 1789,
|
||||
clients_port: 9000,
|
||||
version: config.GATEWAY_VERSION,
|
||||
sphinx_key: config.GATEWAY_SPHINX,
|
||||
identity_key: config.GATEWAY_IDENTITY,
|
||||
location: "earth"
|
||||
};
|
||||
|
||||
const bond = buildCoin("100000000", config.CURRENCY_DENOM)
|
||||
|
||||
try {
|
||||
response = await validatorClient.bondGateway(
|
||||
gateway,
|
||||
config.GATEWAY_SIGNATURE,
|
||||
bond,
|
||||
"auto"
|
||||
);
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
ownsGateway = await validatorClient.client.ownsGateway(config.MIXNET_CONTRACT, config.USER_WALLET_ADDRESS);
|
||||
expect(ownsGateway.gateway?.bond_amount).toStrictEqual(bond.amount);
|
||||
expect(ownsGateway.address).toStrictEqual(config.USER_WALLET_ADDRESS);
|
||||
});
|
||||
|
||||
test.skip("delegate to mixnode, then undelegate", async () => {
|
||||
|
||||
const pledge = buildCoin("100000000", config.CURRENCY_DENOM)
|
||||
|
||||
try {
|
||||
response = await validatorClient.delegateToMixNode(
|
||||
config.MIXNODE_IDENTITY,
|
||||
pledge,
|
||||
"auto"
|
||||
);
|
||||
//todo - we can assert the events for responses
|
||||
response.logs.forEach((log) => {
|
||||
console.log(log.events);
|
||||
console.log(log.log);
|
||||
console.log(log.msg_index);
|
||||
})
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const unbond = await validatorClient.undelegateFromMixNode(
|
||||
config.MIXNODE_IDENTITY,
|
||||
"auto"
|
||||
);
|
||||
|
||||
//todo - we can assert the events for responses
|
||||
unbond.logs.forEach((logs) => {
|
||||
logs.events.forEach((events) => {
|
||||
console.log(events.type);
|
||||
console.log(events.attributes);
|
||||
})
|
||||
});
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,46 +0,0 @@
|
||||
import { Mock, Times } from "moq.ts";
|
||||
import { Block, BlockHeader } from "@cosmjs/stargate";
|
||||
import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
|
||||
|
||||
describe("implement cosmwasm client test", () => {
|
||||
test.only("get height of a block then search for it", async () => {
|
||||
let height = Promise.resolve(200);
|
||||
|
||||
let blockHeader = <BlockHeader>{
|
||||
version: {
|
||||
block: "200",
|
||||
app: "testing",
|
||||
},
|
||||
height: 200,
|
||||
chainId: "nym",
|
||||
time: "today",
|
||||
};
|
||||
|
||||
let block = Promise.resolve(<Block>{
|
||||
header: blockHeader,
|
||||
id: "test",
|
||||
txs: [],
|
||||
});
|
||||
|
||||
const getheight = new Mock<CosmWasmClient>()
|
||||
.setup((nym) => nym.getHeight())
|
||||
.returns(height);
|
||||
|
||||
const getblock = new Mock<CosmWasmClient>()
|
||||
.setup((nym) => nym.getBlock(200))
|
||||
.returns(block);
|
||||
|
||||
let heightC = getheight.object();
|
||||
let blockC = getblock.object();
|
||||
|
||||
let executeHeight = await heightC.getHeight();
|
||||
let executeBlock = await blockC.getBlock(200);
|
||||
|
||||
getheight.verify((nym) => nym.getHeight(), Times.Exactly(1));
|
||||
getblock.verify((nym) => nym.getBlock(200), Times.Exactly(1));
|
||||
|
||||
expect(executeHeight).toStrictEqual(await height);
|
||||
expect(executeBlock.header.height).toStrictEqual(await height);
|
||||
expect(executeBlock.header.chainId).toStrictEqual("nym");
|
||||
});
|
||||
});
|
||||
@@ -1,25 +0,0 @@
|
||||
import { Mock, Times } from "moq.ts";
|
||||
import { INymdQuery } from "../../src/query-client";
|
||||
|
||||
describe("nym-client mocks", () => {
|
||||
test.only("gets interval rewarding percent", async () => {
|
||||
let contract = "mixnet_contract";
|
||||
let response = Promise.resolve(Number(2));
|
||||
|
||||
const client = new Mock<INymdQuery>()
|
||||
.setup((nym) => nym.getIntervalRewardPercent(contract))
|
||||
.returns(response);
|
||||
|
||||
const obj = client.object();
|
||||
|
||||
let execute = await obj.getIntervalRewardPercent(contract);
|
||||
|
||||
client.verify(
|
||||
(nym) => nym.getIntervalRewardPercent(contract),
|
||||
Times.Exactly(1)
|
||||
);
|
||||
|
||||
expect(execute).toStrictEqual(await response);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
import { Coin } from "@cosmjs/proto-signing";
|
||||
import { Mock, Times } from "moq.ts";
|
||||
import ValidatorClient from "../../src/index";
|
||||
import { Gateway, MixNode } from "../../src/types";
|
||||
import { config } from "../test-utils/config";
|
||||
import { buildWallet, buildCoin, profitPercentage } from "../test-utils/utils";
|
||||
import { promiseExecuteResult } from "../test-utils/expectedResults";
|
||||
import { promiseTxResult } from "../test-utils/expectedResults"
|
||||
|
||||
describe("mock validator client tests", () => {
|
||||
test.skip("token transfer", async () => {
|
||||
|
||||
//arrange
|
||||
//todo -- add more here
|
||||
let recipientAddress = "nymt14ev4p8qaa7ayr06cg3z7y2u2kxc9a8f4h9gkch";
|
||||
let sender = "nymt1cv59jumgvz2chn7ffst8tzvnapqzp282m5vat2";
|
||||
|
||||
const coin = buildCoin("50000", "nymt");
|
||||
|
||||
let transaction = promiseTxResult();
|
||||
|
||||
let mockClient = new Mock<ValidatorClient>()
|
||||
.setup((nym) => nym.send(recipientAddress, [coin], "auto", "test")).returns(transaction);
|
||||
|
||||
let token = mockClient.object();
|
||||
|
||||
//act
|
||||
let response = await token.send(recipientAddress, [coin], "auto", "test");
|
||||
|
||||
//assert
|
||||
mockClient.verify(cl => cl.send(recipientAddress, [coin], "auto"), Times.Exactly(1));
|
||||
});
|
||||
|
||||
test.only("bond mixnode test", async () => {
|
||||
//arrange
|
||||
let ownerSignature = "ownersignature";
|
||||
let coin = buildCoin("50000", "nymt");
|
||||
let expectedResult = promiseExecuteResult();
|
||||
|
||||
const profitPercent = profitPercentage();
|
||||
|
||||
const mixnode = <MixNode>{
|
||||
host: "1.1.1.1",
|
||||
mix_port: 1789,
|
||||
verloc_port: 1790,
|
||||
http_api_port: 8080,
|
||||
identity_key: "identity",
|
||||
sphinx_key: "identity",
|
||||
version: "0.12.1",
|
||||
profit_margin_percent: profitPercent,
|
||||
};
|
||||
|
||||
let client = new Mock<ValidatorClient>()
|
||||
.setup((client) =>
|
||||
client.bondMixNode(mixnode, ownerSignature, coin, "auto")
|
||||
)
|
||||
.returns(expectedResult);
|
||||
|
||||
let mixnodeBond = client.object();
|
||||
|
||||
//act
|
||||
let response = await mixnodeBond.bondMixNode(
|
||||
mixnode,
|
||||
ownerSignature,
|
||||
coin,
|
||||
"auto"
|
||||
);
|
||||
client.verify((cl) =>
|
||||
cl.bondMixNode(mixnode, ownerSignature, coin, "auto")
|
||||
);
|
||||
|
||||
//assert
|
||||
expect(response.logs[0].log).toStrictEqual("test");
|
||||
expect(response.transactionHash).toStrictEqual(
|
||||
"9C7BF465AB5CAB0D62446CBB251CF89CD173A640C5DE8DBC14A4BB950916114E"
|
||||
);
|
||||
});
|
||||
|
||||
test.only("un-bond mixnode", async () => {
|
||||
//arrange
|
||||
let expectedResult = promiseExecuteResult();
|
||||
|
||||
let client = new Mock<ValidatorClient>()
|
||||
.setup((client) => client.unbondMixNode("auto"))
|
||||
.returns(expectedResult);
|
||||
|
||||
let unbondNode = client.object();
|
||||
|
||||
//act
|
||||
let response = await unbondNode.unbondMixNode("auto");
|
||||
client.verify((cl) => cl.unbondMixNode("auto"));
|
||||
|
||||
//assert
|
||||
expect(response.logs[0].log).toStrictEqual("test");
|
||||
expect(response.transactionHash).toStrictEqual(
|
||||
"9C7BF465AB5CAB0D62446CBB251CF89CD173A640C5DE8DBC14A4BB950916114E"
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
test.only("bond gateway", async () => {
|
||||
//arrange
|
||||
let expectedResult = promiseExecuteResult();
|
||||
let ownerSignature = "ownersigntature";
|
||||
let coin = buildCoin("50000", "nymt");
|
||||
|
||||
const gateway = <Gateway>{
|
||||
host: '1.2.3.4',
|
||||
mix_port: 1789,
|
||||
clients_port: 9000,
|
||||
version: "0.12.1",
|
||||
sphinx_key: "sphinx_key",
|
||||
identity_key: "identity_key",
|
||||
location: "earth"
|
||||
};
|
||||
|
||||
let client = new Mock<ValidatorClient>()
|
||||
.setup((client) => client.bondGateway(gateway, ownerSignature, coin, "auto", "memo"))
|
||||
.returns(expectedResult);
|
||||
|
||||
let mock = client.object();
|
||||
|
||||
//act
|
||||
let response = await mock.bondGateway(gateway, ownerSignature, coin, "auto", "memo");
|
||||
client.verify((cl) => cl.bondGateway(gateway, ownerSignature, coin, "auto", "memo"));
|
||||
|
||||
//assert
|
||||
expect(response.logs[0].log).toStrictEqual("test");
|
||||
expect(response.transactionHash).toStrictEqual(
|
||||
"9C7BF465AB5CAB0D62446CBB251CF89CD173A640C5DE8DBC14A4BB950916114E"
|
||||
);
|
||||
});
|
||||
|
||||
test.only("unbond gateway", async () => {
|
||||
//arrange
|
||||
let expectedResult = promiseExecuteResult();
|
||||
let client = new Mock<ValidatorClient>()
|
||||
.setup((client) => client.unbondGateway())
|
||||
.returns(expectedResult);
|
||||
|
||||
let mock = client.object();
|
||||
|
||||
//act
|
||||
let response = await mock.unbondGateway();
|
||||
client.verify((cl) => cl.unbondGateway());
|
||||
|
||||
//assert
|
||||
expect(response.logs[0].log).toStrictEqual("test");
|
||||
expect(response.transactionHash).toStrictEqual(
|
||||
"9C7BF465AB5CAB0D62446CBB251CF89CD173A640C5DE8DBC14A4BB950916114E"
|
||||
);
|
||||
});
|
||||
|
||||
test.only("retrieve a newly created account and the balance should be empty", async () => {
|
||||
let nymWallet = await buildWallet();
|
||||
|
||||
let coin = Promise.resolve(<Coin>{
|
||||
denom: `${config.CURRENCY_DENOM}`,
|
||||
amount: "0",
|
||||
});
|
||||
|
||||
let client = new Mock<ValidatorClient>()
|
||||
.setup((nym) => nym.getBalance(nymWallet))
|
||||
.returns(coin);
|
||||
|
||||
let obj = client.object();
|
||||
|
||||
let execute = await obj.getBalance(nymWallet);
|
||||
|
||||
client.verify((nym) => nym.getBalance(nymWallet), Times.Exactly(1));
|
||||
|
||||
expect(execute).toStrictEqual(await coin);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
export const config = {
|
||||
NYMD_URL: process.env.NYMD_URL as string,
|
||||
VALIDATOR_API: process.env.VALIDATOR_API as string,
|
||||
MIXNET_CONTRACT: process.env.MIXNET_CONTRACT as string,
|
||||
VESTING_CONTRACT: process.env.VESTING_CONTRACT as string,
|
||||
USER_MNEMONIC: process.env.USER_MNEMONIC as string,
|
||||
USER_WALLET_ADDRESS: process.env.USER_WALLET_ADDRESS as string,
|
||||
CURRENCY_DENOM: process.env.CURRENCY_DENOM as string,
|
||||
CHAIN_ID: process.env.CHAIN_ID as string,
|
||||
MIXNODE_IDENTITY: process.env.MIXNODE_IDENTITY as string,
|
||||
MIXNODE_SPHINX_KEY: process.env.MIXNODE_SPHINX_KEY as string,
|
||||
MIXNODE_SIGNATURE: process.env.MIXNODE_SIGNATURE as string,
|
||||
MIXNODE_HOST: process.env.MIXNODE_HOST as string,
|
||||
MIXNODE_VERSION: process.env.MIXNODE_VERSION as string,
|
||||
GATEWAY_IDENTITY: process.env.GATEWAY_IDENTITY as string,
|
||||
GATEWAY_SIGNATURE: process.env.GATEWAY_SIGNATURE as string,
|
||||
GATEWAY_SPHINX: process.env.GATEWAY_SPHINX as string,
|
||||
GATEWAY_LOCATION: process.env.GATEWAY_LOCATION as string,
|
||||
GATEWAY_HOST: process.env.GATEWAY_HOST as string,
|
||||
GATEWAY_VERSION: process.env.GATEWAY_VERSION as string,
|
||||
NETWORK_BECH: process.env.NETWORK_BECH as string,
|
||||
};
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { ExecuteResult } from "@cosmjs/cosmwasm-stargate";
|
||||
import { DeliverTxResponse, logs } from "@cosmjs/stargate";
|
||||
|
||||
export const promiseExecuteResult = (): Promise<ExecuteResult> => {
|
||||
let log = <logs.Log>{
|
||||
msg_index: 0,
|
||||
log: "test",
|
||||
events: [],
|
||||
};
|
||||
return Promise.resolve(<ExecuteResult>{
|
||||
logs: [log],
|
||||
transactionHash:
|
||||
"9C7BF465AB5CAB0D62446CBB251CF89CD173A640C5DE8DBC14A4BB950916114E",
|
||||
});
|
||||
};
|
||||
|
||||
export const promiseTxResult = (): Promise<DeliverTxResponse> => {
|
||||
return Promise.resolve(<DeliverTxResponse>{
|
||||
code: 0,
|
||||
height: 1208302,
|
||||
rawLog: "[]",
|
||||
transactionHash:
|
||||
"9C7BF465AB5CAB0D62446CBB251CF89CD173A640C5DE8DBC14A4BB950916114E",
|
||||
gasUsed: 65042,
|
||||
gasWanted: 67977,
|
||||
});
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
// timer actions
|
||||
|
||||
import ValidatorClient, { Coin } from "../../src";
|
||||
import { config } from "./config";
|
||||
|
||||
// Store current time as `start`
|
||||
export const now = (eventName = null) => {
|
||||
if (eventName) {
|
||||
console.log(`Started ${eventName}..`);
|
||||
}
|
||||
return new Date().getTime();
|
||||
};
|
||||
|
||||
//takes arg of start time
|
||||
export const elapsed = (beginning: number, log = false) => {
|
||||
const duration = new Date().getTime() - beginning;
|
||||
if (log) {
|
||||
console.log(`${duration / 1000}s`);
|
||||
}
|
||||
return duration;
|
||||
};
|
||||
|
||||
export const profitPercentage = (): number => {
|
||||
return Math.floor(Math.random() * 100) + 1;
|
||||
};
|
||||
|
||||
|
||||
export const buildCoin = (amount: string, denomination: string): Coin => {
|
||||
return {
|
||||
denom: `u${denomination}`,
|
||||
amount: amount,
|
||||
};
|
||||
};
|
||||
|
||||
export const buildWallet = async (): Promise<string> => {
|
||||
let mnemonic = ValidatorClient.randomMnemonic();
|
||||
|
||||
const randomAddress = await ValidatorClient.buildWallet(
|
||||
mnemonic,
|
||||
config.NETWORK_BECH
|
||||
);
|
||||
let accountdetails = await randomAddress.getAccounts();
|
||||
let nymWallet = accountdetails[0].address;
|
||||
return nymWallet;
|
||||
};
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
const currency = require("../../src/currency");
|
||||
|
||||
describe("currency module tests", () => {
|
||||
test.skip("convert to native balance", () => {
|
||||
const decimal = "12.0346";
|
||||
const value = currency.printableBalanceToNative(decimal);
|
||||
|
||||
expect(value).toStrictEqual("12034600");
|
||||
});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
const stargate = require("../../src/stargate-helper");
|
||||
import { config } from "../test-utils/config";
|
||||
|
||||
describe("test the stargate functions within the project", () => {
|
||||
test.skip("gas price is returned correctly", () => {
|
||||
const nymCurrency = config.CURRENCY_DENOM;
|
||||
const getGasPrice = stargate.nymGasPrice(nymCurrency);
|
||||
|
||||
expect(getGasPrice.denom).toBe(`u${nymCurrency}`);
|
||||
});
|
||||
|
||||
test.skip("provide invalid type returns an error message", () => {
|
||||
//pass invalid type
|
||||
expect(() => {
|
||||
const nymCurrency = 13;
|
||||
stargate.nymGasPrice(nymCurrency);
|
||||
}).toThrow("13 is not of type string");
|
||||
});
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
import validator from "../../src/index";
|
||||
|
||||
describe("validator build network mnemonic", () => {
|
||||
test.skip("get mnemonic", async () => {
|
||||
const mnemonic = validator.randomMnemonic();
|
||||
const mnemonicCount = mnemonic.split(" ").length;
|
||||
|
||||
expect(mnemonicCount).toStrictEqual(24);
|
||||
});
|
||||
});
|
||||
@@ -5,11 +5,7 @@
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"types": [
|
||||
"jest",
|
||||
"node",
|
||||
]
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"typedocOptions": {
|
||||
"entryPoints": [
|
||||
@@ -20,11 +16,7 @@
|
||||
"exclude": [
|
||||
"dist",
|
||||
"examples",
|
||||
"node_modules"
|
||||
],
|
||||
"include": [
|
||||
"tests",
|
||||
"./tests/*/*.tsx",
|
||||
"./tests/*/*.ts"
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
+2895
-3590
File diff suppressed because it is too large
Load Diff
@@ -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 = "2021"
|
||||
edition = "2018"
|
||||
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.78", features = ["serde-serialize"] }
|
||||
wasm-bindgen = { version = "0.2", 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", default-features = false, features = ["wasm"] }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||
validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
|
||||
wasm-utils = { path = "../../common/wasm-utils" }
|
||||
|
||||
|
||||
+18
-6578
File diff suppressed because it is too large
Load Diff
+627
-508
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@
|
||||
"@testing-library/react": "^9.5.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
"bootstrap": "^4.5.0",
|
||||
"node-sass": "^7.0.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-scripts": "^4.0.0",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
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;
|
||||
@@ -110,7 +111,7 @@ impl NymClient {
|
||||
let testnet_mode = self.testnet_mode;
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
let bandwidth_controller = Some(gateway_client::bandwidth::BandwidthController::new(
|
||||
let bandwidth_controller = Some(BandwidthController::new(
|
||||
vec![self.validator_server.clone()],
|
||||
*self.identity.public_key(),
|
||||
));
|
||||
@@ -127,7 +128,6 @@ 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 = "2021"
|
||||
edition = "2018"
|
||||
|
||||
# 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 = "2021"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -15,15 +15,12 @@ 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" }
|
||||
|
||||
@@ -39,6 +36,12 @@ 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"
|
||||
@@ -67,6 +70,4 @@ features = ["js"]
|
||||
#url = "2.1"
|
||||
|
||||
[features]
|
||||
coconut = ["gateway-requests/coconut", "coconut-interface"]
|
||||
wasm = ["web3/wasm", "web3/http", "web3/signing"]
|
||||
default = ["web3/default"]
|
||||
coconut = ["gateway-requests/coconut", "coconut-interface"]
|
||||
@@ -16,27 +16,22 @@ use crypto::asymmetric::identity::PublicKey;
|
||||
use network_defaults::BANDWIDTH_VALUE;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use network_defaults::{
|
||||
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,
|
||||
eth_contract::ETH_JSON_ABI, ETH_BURN_FUNCTION_NAME, ETH_CONTRACT_ADDRESS, ETH_MIN_BLOCK_DEPTH,
|
||||
TOKENS_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::{Read, Write};
|
||||
use std::io::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, U256, U64},
|
||||
types::{Address, Bytes, U256, U64},
|
||||
Web3,
|
||||
};
|
||||
|
||||
@@ -55,19 +50,6 @@ 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")]
|
||||
@@ -77,8 +59,6 @@ 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,
|
||||
@@ -104,14 +84,12 @@ 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.clone());
|
||||
let erc20_contract = eth_erc20_contract(web3);
|
||||
let contract = eth_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,
|
||||
})
|
||||
@@ -129,45 +107,6 @@ 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,
|
||||
@@ -206,25 +145,17 @@ impl BandwidthController {
|
||||
pub async fn prepare_token_credential(
|
||||
&self,
|
||||
gateway_identity: PublicKey,
|
||||
gateway_owner: String,
|
||||
) -> Result<TokenCredential, GatewayClientError> {
|
||||
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 mut rng = OsRng;
|
||||
|
||||
let kp = identity::KeyPair::new(&mut rng);
|
||||
self.backup_keypair(&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, gateway_owner)
|
||||
self.buy_token_credential(verification_key, signed_verification_key)
|
||||
.await?;
|
||||
|
||||
self.mark_keypair_as_spent(&kp)?;
|
||||
|
||||
let message: Vec<u8> = verification_key
|
||||
.to_bytes()
|
||||
.iter()
|
||||
@@ -246,114 +177,33 @@ 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 + 20 seconds of wait for kill
|
||||
// 15 seconds per confirmation block + 10 seconds of network overhead
|
||||
log::info!(
|
||||
"Waiting for Ethereum transaction. This should take about {} seconds",
|
||||
(confirmations + 1) * 15 + 30
|
||||
confirmations * 15 + 10
|
||||
);
|
||||
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,
|
||||
(
|
||||
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),
|
||||
U256::from(TOKENS_TO_BURN),
|
||||
U256::from(&verification_key.to_bytes()),
|
||||
Bytes(signed_verification_key.to_bytes().to_vec()),
|
||||
),
|
||||
options,
|
||||
Options::default(),
|
||||
confirmations,
|
||||
&self.eth_private_key,
|
||||
)
|
||||
.await?;
|
||||
if Some(U64::from(0u64)) == recipt.status {
|
||||
if Some(U64::from(0)) == recipt.status {
|
||||
Err(GatewayClientError::BurnTokenError(
|
||||
web3::Error::InvalidResponse(format!(
|
||||
"Transaction status is 0 (failure): {:?}",
|
||||
@@ -386,15 +236,6 @@ 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,7 +20,6 @@ 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;
|
||||
@@ -45,7 +44,6 @@ 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,
|
||||
@@ -70,7 +68,6 @@ 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,
|
||||
@@ -83,7 +80,6 @@ impl GatewayClient {
|
||||
bandwidth_remaining: 0,
|
||||
gateway_address,
|
||||
gateway_identity,
|
||||
gateway_owner,
|
||||
local_identity,
|
||||
shared_key,
|
||||
connection: SocketState::NotConnected,
|
||||
@@ -116,7 +112,6 @@ 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 {
|
||||
@@ -134,7 +129,6 @@ impl GatewayClient {
|
||||
bandwidth_remaining: 0,
|
||||
gateway_address,
|
||||
gateway_identity,
|
||||
gateway_owner,
|
||||
local_identity,
|
||||
shared_key: None,
|
||||
connection: SocketState::NotConnected,
|
||||
@@ -554,8 +548,6 @@ impl GatewayClient {
|
||||
return self.try_claim_testnet_bandwidth().await;
|
||||
}
|
||||
|
||||
let _gateway_owner = self.gateway_owner.clone();
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
let credential = self
|
||||
.bandwidth_controller
|
||||
@@ -568,7 +560,7 @@ impl GatewayClient {
|
||||
.bandwidth_controller
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.prepare_token_credential(self.gateway_identity, _gateway_owner)
|
||||
.prepare_token_credential(self.gateway_identity)
|
||||
.await?;
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
@@ -592,10 +584,15 @@ impl GatewayClient {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
}
|
||||
if self.estimate_required_bandwidth(&packets) > self.bandwidth_remaining {
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
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,
|
||||
));
|
||||
}
|
||||
}
|
||||
if !self.connection.is_established() {
|
||||
return Err(GatewayClientError::ConnectionNotEstablished);
|
||||
@@ -662,10 +659,15 @@ impl GatewayClient {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
}
|
||||
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,
|
||||
));
|
||||
// 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,
|
||||
));
|
||||
}
|
||||
}
|
||||
if !self.connection.is_established() {
|
||||
return Err(GatewayClientError::ConnectionNotEstablished);
|
||||
@@ -735,12 +737,6 @@ 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::{contract::Error as Web3ContractError, Error as Web3Error};
|
||||
use web3::Error as Web3Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GatewayClientError {
|
||||
@@ -27,17 +27,13 @@ pub enum GatewayClientError {
|
||||
NetworkErrorWasm(JsValue),
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[error("Keypair IO error - {0}")]
|
||||
#[error("Could not backup keypair - {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 = "2021"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -41,17 +41,6 @@ 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,
|
||||
@@ -197,10 +186,10 @@ impl Client {
|
||||
.await
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl SendWithoutResponse for Client {
|
||||
fn send_without_response(
|
||||
// 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(
|
||||
&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, SendWithoutResponse};
|
||||
use crate::client::{Client, Config};
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
pub mod client;
|
||||
pub mod forwarder;
|
||||
|
||||
pub use client::{Client, Config, SendWithoutResponse};
|
||||
pub use client::{Client, Config};
|
||||
|
||||
@@ -2,26 +2,24 @@
|
||||
name = "validator-client"
|
||||
version = "0.1.0"
|
||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
edition = "2018"
|
||||
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-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"] }
|
||||
mixnet-contract = { path="../../../common/mixnet-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
|
||||
@@ -29,29 +27,14 @@ validator-api-requests = { path = "../../../validator-api/validator-api-requests
|
||||
async-trait = { version = "0.1.51", optional = true }
|
||||
bip39 = { version = "1", features = ["rand"], optional = true }
|
||||
config = { path = "../../config", optional = true }
|
||||
cosmrs = { version = "0.4.1", features = [
|
||||
"rpc",
|
||||
"bip32",
|
||||
"cosmwasm",
|
||||
], 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 }
|
||||
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 }
|
||||
# Leaving it as * so that it inherits whatever the wallet is using
|
||||
ts-rs = { version = "*", optional = true }
|
||||
ts-rs = {version = "5.1", optional = true}
|
||||
|
||||
[features]
|
||||
nymd-client = [
|
||||
"async-trait",
|
||||
"bip39",
|
||||
"config",
|
||||
"cosmrs",
|
||||
"prost",
|
||||
"flate2",
|
||||
"sha2",
|
||||
"itertools",
|
||||
"cosmwasm-std",
|
||||
]
|
||||
typescript-types = ["ts-rs", "validator-api-requests/ts-rs"]
|
||||
nymd-client = ["async-trait", "bip39", "config", "cosmrs", "prost", "flate2", "sha2", "itertools", "cosmwasm-std"]
|
||||
|
||||
@@ -1,69 +1,53 @@
|
||||
// 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, MixNodeBond};
|
||||
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_common::ContractStateParams;
|
||||
use mixnet_contract::ContractStateParams;
|
||||
|
||||
use crate::{validator_api, ValidatorClientError};
|
||||
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use mixnet_contract_common::{
|
||||
Delegation, IdentityKey, Interval, MixnetContractVersion, MixnodeRewardingStatusResponse,
|
||||
RewardedSetNodeStatus, RewardedSetUpdateDetails,
|
||||
use mixnet_contract::{
|
||||
Delegation, MixnetContractVersion, MixnodeRewardingStatusResponse, RewardingIntervalResponse,
|
||||
};
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use mixnet_contract::{GatewayBond, MixNodeBond};
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
#[must_use]
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,25 +65,17 @@ 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> {
|
||||
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,
|
||||
@@ -114,25 +90,20 @@ 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,
|
||||
})
|
||||
@@ -140,11 +111,9 @@ 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,
|
||||
)?;
|
||||
@@ -158,37 +127,23 @@ 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(),
|
||||
Some(config.mixnet_contract_address.clone().unwrap_or_else(|| {
|
||||
config.mixnet_contract_address.clone().unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(network_defaults::DEFAULT_MIXNET_CONTRACT_ADDRESS)
|
||||
.unwrap()
|
||||
})),
|
||||
Some(config.vesting_contract_address.clone().unwrap_or_else(|| {
|
||||
}),
|
||||
config.vesting_contract_address.clone().unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(network_defaults::DEFAULT_VESTING_CONTRACT_ADDRESS)
|
||||
.unwrap()
|
||||
})),
|
||||
Some(
|
||||
config
|
||||
.erc20_bridge_contract_address
|
||||
.clone()
|
||||
.unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(
|
||||
network_defaults::DEFAULT_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,
|
||||
})
|
||||
@@ -197,9 +152,8 @@ 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(),
|
||||
self.vesting_contract_address.clone(),
|
||||
self.erc20_bridge_contract_address.clone(),
|
||||
self.mixnet_contract_address.clone().unwrap(),
|
||||
self.vesting_contract_address.clone().unwrap(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -225,18 +179,6 @@ 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?)
|
||||
}
|
||||
@@ -252,12 +194,21 @@ impl<C> Client<C> {
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
self.nymd.get_mixnet_contract_version().await
|
||||
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?)
|
||||
}
|
||||
|
||||
pub async fn get_rewarding_status(
|
||||
&self,
|
||||
mix_identity: mixnet_contract_common::IdentityKey,
|
||||
mix_identity: mixnet_contract::IdentityKey,
|
||||
rewarding_interval_nonce: u32,
|
||||
) -> Result<MixnodeRewardingStatusResponse, ValidatorClientError>
|
||||
where
|
||||
@@ -276,13 +227,6 @@ impl<C> Client<C> {
|
||||
Ok(self.nymd.get_reward_pool().await?.u128())
|
||||
}
|
||||
|
||||
pub async fn get_current_interval(&self) -> Result<Interval, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.nymd.get_current_interval().await?)
|
||||
}
|
||||
|
||||
pub async fn get_circulating_supply(&self) -> Result<u128, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
@@ -297,136 +241,14 @@ impl<C> Client<C> {
|
||||
Ok(self.nymd.get_sybil_resistance_percent().await?)
|
||||
}
|
||||
|
||||
pub async fn get_active_set_work_factor(&self) -> Result<u8, ValidatorClientError>
|
||||
pub async fn get_epoch_reward_percent(&self) -> Result<u8, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.nymd.get_active_set_work_factor().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?)
|
||||
Ok(self.nymd.get_epoch_reward_percent().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,
|
||||
@@ -475,8 +297,8 @@ impl<C> Client<C> {
|
||||
|
||||
pub async fn get_all_nymd_single_mixnode_delegations(
|
||||
&self,
|
||||
identity: IdentityKey,
|
||||
) -> Result<Vec<Delegation>, ValidatorClientError>
|
||||
identity: mixnet_contract::IdentityKey,
|
||||
) -> Result<Vec<mixnet_contract::Delegation>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
@@ -598,12 +420,6 @@ 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?)
|
||||
}
|
||||
@@ -612,55 +428,6 @@ 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,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user