Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c835ab24fd |
@@ -69,7 +69,7 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --release --all
|
||||
args: --workspace --release
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -79,9 +79,6 @@ jobs:
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Install wasm-opt
|
||||
run: cargo install wasm-opt
|
||||
|
||||
- name: Build release contracts
|
||||
run: make wasm
|
||||
|
||||
@@ -98,8 +95,7 @@ jobs:
|
||||
cp target/release/nym-network-requester $OUTPUT_DIR
|
||||
cp target/release/nym-network-statistics $OUTPUT_DIR
|
||||
cp target/release/nym-cli $OUTPUT_DIR
|
||||
cp target/release/credential $OUTPUT_DIR
|
||||
|
||||
|
||||
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm $OUTPUT_DIR
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
name: Run config checks on all binaries
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
push:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
- 'common/**'
|
||||
- 'contracts/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
- 'common/**'
|
||||
- 'gateway/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [custom-runner-linux]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get -y install jq vim libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Branch name
|
||||
run: echo running on branch ${GITHUB_REF##*/}
|
||||
|
||||
- name: Run tests against binaries
|
||||
run: ./build_and_run.sh ${{ github.head_ref || github.ref_name }}
|
||||
working-directory: tests/
|
||||
|
||||
|
||||
@@ -23,12 +23,15 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install \
|
||||
libwebkit2gtk-4.0-dev \
|
||||
build-essential \
|
||||
unzip \
|
||||
curl \
|
||||
wget \
|
||||
libssl-dev \
|
||||
libgtk-3-dev \
|
||||
squashfs-tools \
|
||||
libayatana-appindicator3-dev \
|
||||
librsvg2-dev
|
||||
|
||||
- name: Checkout
|
||||
@@ -61,11 +64,6 @@ jobs:
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
# TODO this step takes a considerable amount of time
|
||||
# We could avoid to compile from source tauri-cli and use instead
|
||||
# pre-compiled binary provided by the node package `@tauri-apps/cli`
|
||||
# But when using the later the build fails for some reason
|
||||
# so keep installing and using tauri-cli
|
||||
- name: Install tauri cli
|
||||
run: cargo install tauri-cli --version "^2.0.0-alpha.2"
|
||||
|
||||
@@ -95,13 +93,11 @@ jobs:
|
||||
- name: Build APK
|
||||
working-directory: nym-connect/mobile
|
||||
env:
|
||||
# NODE_TAURI_CLI=${{ github.workspace }}/nym-connect/mobile/node_modules/.bin/tauri
|
||||
ANDROID_SDK_ROOT: ${{ env.ANDROID_HOME }}
|
||||
WRY_ANDROID_PACKAGE: net.nymtech.nym_connect
|
||||
WRY_ANDROID_LIBRARY: nym_connect
|
||||
# TODO build with release profile (--release), it will requires
|
||||
# to sign the APK. For now build with debug profile to avoid that
|
||||
# TODO build using `yarn tauri`, provide NODE_TAURI_CLI, see TODO notes above
|
||||
run: cargo tauri android build --debug --apk --split-per-abi -t aarch64
|
||||
|
||||
# TODO add the version number to APK name
|
||||
|
||||
@@ -49,6 +49,7 @@ jobs:
|
||||
librsvg2-dev \
|
||||
libsoup-3.0-dev \
|
||||
libjavascriptcoregtk-4.1-dev
|
||||
#continue-on-error: true
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release' }}
|
||||
runs-on: [self-hosted, custom-runner-linux]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -19,9 +19,6 @@ jobs:
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Install wasm-opt
|
||||
run: cargo install wasm-opt
|
||||
|
||||
- name: Build release contracts
|
||||
run: make wasm
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
name: CI for Network Explorer API
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-explorer-api-') && (github.event_name == 'release' || github.event_name == 'workflow_dispatch') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-20.04]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
|
||||
continue-on-error: true
|
||||
|
||||
- name: Check the release tag starts with `nym-explorer-api-`
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-explorer-api-...')
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Build all explorer-api
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path explorer-api/Cargo.toml --workspace --release
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: my-artifact
|
||||
path: |
|
||||
target/release/explorer-api
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
target/release/explorer-api
|
||||
@@ -0,0 +1,50 @@
|
||||
name: Publish Nym CLI binaries
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
|
||||
jobs:
|
||||
publish-nym-cli:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-cli-') && (github.event_name == 'release' || github.event_name == 'workflow_dispatch') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-20.04, windows-latest, macos-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Check the release tag starts with `nym-cli-`
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-cli-...')
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Build binary
|
||||
run: make build-nym-cli
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-cli-${{ matrix.platform }}
|
||||
path: |
|
||||
target/release/nym-cli*
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
target/release/nym-cli
|
||||
@@ -10,7 +10,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -10,7 +10,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -16,7 +16,7 @@ env:
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -10,7 +10,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -9,7 +9,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> 🔴 **FAILURE** :cry:
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message:
|
||||
```
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
||||
>
|
||||
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION_STORYBOOK }}.{{ env.NYM_CI_WWW_BASE }}
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||
```
|
||||
|
||||
@@ -151,7 +151,7 @@ async function getMessageBody(context) {
|
||||
return `${icon} ${job.conclusion}: ${job.name} - ${job.html_url}`;
|
||||
})
|
||||
// and join with newlines for display in the template
|
||||
.join('\n\n');
|
||||
.join('\n');
|
||||
|
||||
return template({ ...context, jobResults });
|
||||
}
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> 🔴 **FAILURE** :cry:
|
||||
>
|
||||
> `when` {{ timestamp }}
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
{{ jobResults }}
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
>
|
||||
> `when` {{ timestamp }}
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
{{ jobResults }}
|
||||
{{ jobResults }}
|
||||
@@ -5,7 +5,6 @@ const localStorage = new LocalStorage('./scratch');
|
||||
const {
|
||||
LocalStorageCryptoStore,
|
||||
} = require('matrix-js-sdk/lib/crypto/store/localStorage-crypto-store');
|
||||
var showdown = require('showdown');
|
||||
|
||||
// hide all matrix client output
|
||||
console.error = (error) => console.log('❌ error: ', error);
|
||||
@@ -55,9 +54,7 @@ function createClient(context, room, message) {
|
||||
}
|
||||
|
||||
async function sendMatrixMessage(contextArg, messageAsMarkdown, roomId) {
|
||||
const converter = new showdown.Converter();
|
||||
const messageAsHtml = converter.makeHtml(messageAsMarkdown);
|
||||
const client = createClient(contextArg, roomId, messageAsHtml);
|
||||
const client = createClient(contextArg, roomId, messageAsMarkdown);
|
||||
await client.initCrypto();
|
||||
await client.startClient({ initialSyncLimit: 1 });
|
||||
}
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> 🔴 **FAILURE** :cry:
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message:
|
||||
```
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View storybook:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||
```
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> 🔴 **FAILURE** :cry:
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message:
|
||||
```
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
>
|
||||
|
||||
> ➡️➡️➡️➡️➡️ **View output:**
|
||||
>
|
||||
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}
|
||||
>
|
||||
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||
```
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
"remark-emoji": "^2.2.0",
|
||||
"remark-html": "^13.0.2",
|
||||
"remark-parse": "^9.0.0",
|
||||
"showdown": "^2.1.0",
|
||||
"to-vfile": "^6.1.0",
|
||||
"unified": "^9.2.2"
|
||||
},
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> 🔴 **FAILURE** :cry:
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message:
|
||||
```
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
>
|
||||
|
||||
> ➡️➡️➡️➡️➡️ **View output:**
|
||||
>
|
||||
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}
|
||||
>
|
||||
> `example`: https://{{ env.NYM_CI_WWW_LOCATION }}-example.{{ env.NYM_CI_WWW_BASE }}
|
||||
>
|
||||
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||
```
|
||||
|
||||
@@ -43,4 +43,3 @@ Cargo.lock
|
||||
nym-connect/Cargo.lock
|
||||
.parcel-cache
|
||||
**/.DS_Store
|
||||
cpu-cycles/libcpucycles/build
|
||||
+1
-15
@@ -4,21 +4,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.1.12] (2023-03-07)
|
||||
|
||||
- Fix generated docs for mixnet and vesting contract on docs.rs ([#3093])
|
||||
- Introduce a way of injecting topology into the client ([#3044])
|
||||
- Update mixnet TypeScript client methods #1 ([#2783])
|
||||
- Update tooltips for routing and average score ([#3133])
|
||||
- update selected service provider description style ([#3128])
|
||||
|
||||
[#3093]: https://github.com/nymtech/nym/issues/3093
|
||||
[#3044]: https://github.com/nymtech/nym/issues/3044
|
||||
[#2783]: https://github.com/nymtech/nym/issues/2783
|
||||
[#3133]: https://github.com/nymtech/nym/pull/3133
|
||||
[#3128]: https://github.com/nymtech/nym/pull/3128
|
||||
|
||||
## [v1.1.11] (2023-02-28)
|
||||
## [v1.0.11] (2023-02-28)
|
||||
|
||||
- Fix empty dealer set loop ([#3105])
|
||||
- The nym-api db.sqlite is broken when trying to run against it it in `enabled-credentials-mode true` there is an ordering issue with migrations when using the credential binary to purchase bandwidth ([#3100])
|
||||
|
||||
Generated
+397
-251
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -22,6 +22,7 @@ members = [
|
||||
"clients/native",
|
||||
"clients/native/websocket-requests",
|
||||
"clients/socks5",
|
||||
"common/bandwidth-claim-contract",
|
||||
"common/bin-common",
|
||||
"common/client-libs/gateway-client",
|
||||
"common/client-libs/mixnet-client",
|
||||
@@ -104,9 +105,9 @@ edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
async-trait = "0.1.64"
|
||||
async-trait = "0.1.63"
|
||||
cfg-if = "1.0.0"
|
||||
dotenvy = "0.15.6"
|
||||
dotenv = "0.15.0"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4"
|
||||
once_cell = "1.7.2"
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
test: clippy-all cargo-test wasm fmt
|
||||
test-no-mobile: clippy-all-no-mobile cargo-test-no-mobile wasm fmt-no-mobile
|
||||
test-all: test cargo-test-expensive
|
||||
test-all-no-mobile: test-no-mobile cargo-test-expensive
|
||||
no-clippy: build cargo-test wasm fmt
|
||||
no-clippy-no-mobile: build-no-mobile cargo-test-no-mobile wasm fmt-no-mobile
|
||||
happy: fmt clippy-happy test
|
||||
happy-no-mobile: fmt-no-mobile clippy-happy-no-mobile test-no-mobile
|
||||
clippy-all: clippy-all-no-mobile clippy-all-connect-mobile
|
||||
clippy-all-no-mobile: clippy-main clippy-main-examples clippy-all-contracts clippy-all-wallet clippy-all-connect clippy-all-wasm-client
|
||||
clippy-happy: clippy-happy-no-mobile clippy-happy-connect-mobile
|
||||
clippy-happy-no-mobile: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect
|
||||
cargo-test: cargo-test-no-mobile test-connect-mobile
|
||||
cargo-test-no-mobile: test-main test-contracts test-wallet test-connect
|
||||
clippy-all: clippy-main clippy-main-examples clippy-all-contracts clippy-all-wallet clippy-all-connect clippy-all-connect-mobile clippy-all-wasm-client
|
||||
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect clippy-happy-connect-mobile
|
||||
cargo-test: test-main test-contracts test-wallet test-connect test-connect-mobile
|
||||
cargo-test-expensive: test-main-expensive test-contracts-expensive test-wallet-expensive test-connect-expensive
|
||||
build: build-no-mobile build-connect-mobile
|
||||
build-no-mobile: build-contracts build-wallet build-main build-main-examples build-connect build-wasm-client
|
||||
fmt: fmt-no-mobile fmt-connect-mobile
|
||||
fmt-no-mobile: fmt-main fmt-contracts fmt-wallet fmt-connect fmt-wasm-client
|
||||
build: build-contracts build-wallet build-main build-main-examples build-connect build-connect-mobile build-wasm-client
|
||||
fmt: fmt-main fmt-contracts fmt-wallet fmt-connect fmt-connect-mobile fmt-wasm-client
|
||||
|
||||
clippy-happy-main:
|
||||
cargo clippy
|
||||
@@ -135,8 +126,6 @@ fmt-wasm-client:
|
||||
|
||||
wasm:
|
||||
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
|
||||
wasm-opt -Os contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm -o contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm
|
||||
wasm-opt -Os contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm -o contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm
|
||||
|
||||
mixnet-opt: wasm
|
||||
cd contracts/mixnet && make opt
|
||||
|
||||
@@ -16,7 +16,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
||||
[](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
||||
|
||||
|
||||
### Building
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "client-core"
|
||||
version = "1.1.12"
|
||||
version = "1.1.11"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.66"
|
||||
@@ -8,7 +8,7 @@ rust-version = "1.66"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
async-trait = { version = "0.1.58" }
|
||||
dirs = "4.0"
|
||||
dashmap = "5.4.0"
|
||||
futures = "0.3"
|
||||
@@ -37,10 +37,6 @@ nym-topology = { path = "../../common/topology" }
|
||||
validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
|
||||
nym-task = { path = "../../common/task" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.validator-client]
|
||||
path = "../../common/client-libs/validator-client"
|
||||
features = ["nyxd-client"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
|
||||
version = "0.1.11"
|
||||
features = ["time"]
|
||||
|
||||
@@ -15,7 +15,6 @@ use crate::client::replies::reply_controller::{ReplyControllerReceiver, ReplyCon
|
||||
use crate::client::replies::reply_storage::{
|
||||
CombinedReplyStorage, PersistentReplyStorage, ReplyStorageBackend, SentReplyKeys,
|
||||
};
|
||||
use crate::client::topology_control::nym_api_provider::NymApiTopologyProvider;
|
||||
use crate::client::topology_control::{
|
||||
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
|
||||
};
|
||||
@@ -38,12 +37,10 @@ use nym_sphinx::addressing::nodes::NodeIdentity;
|
||||
use nym_sphinx::receiver::ReconstructedMessage;
|
||||
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
|
||||
use nym_task::{TaskClient, TaskManager};
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tap::TapFallible;
|
||||
use url::Url;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use validator_client::nyxd::CosmWasmClient;
|
||||
|
||||
@@ -93,7 +90,6 @@ impl ClientOutput {
|
||||
pub struct ClientState {
|
||||
pub shared_lane_queue_lengths: LaneQueueLengths,
|
||||
pub reply_controller_sender: ReplyControllerSender,
|
||||
pub topology_accessor: TopologyAccessor,
|
||||
}
|
||||
|
||||
pub enum ClientInputStatus {
|
||||
@@ -158,7 +154,6 @@ pub struct BaseClientBuilder<'a, B, C: Clone> {
|
||||
nym_api_endpoints: Vec<Url>,
|
||||
reply_storage_backend: B,
|
||||
|
||||
custom_topology_provider: Option<Box<dyn TopologyProvider>>,
|
||||
bandwidth_controller: Option<BandwidthController<C>>,
|
||||
key_manager: KeyManager,
|
||||
}
|
||||
@@ -182,7 +177,6 @@ where
|
||||
bandwidth_controller,
|
||||
reply_storage_backend,
|
||||
key_manager,
|
||||
custom_topology_provider: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,17 +195,11 @@ where
|
||||
disabled_credentials: credentials_toggle.is_disabled(),
|
||||
nym_api_endpoints,
|
||||
reply_storage_backend,
|
||||
custom_topology_provider: None,
|
||||
bandwidth_controller,
|
||||
key_manager,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_topology_provider(mut self, provider: Box<dyn TopologyProvider>) -> Self {
|
||||
self.custom_topology_provider = Some(provider);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn as_mix_recipient(&self) -> Recipient {
|
||||
Recipient::new(
|
||||
*self.key_manager.identity_keypair().public_key(),
|
||||
@@ -353,38 +341,25 @@ where
|
||||
Ok(gateway_client)
|
||||
}
|
||||
|
||||
fn setup_topology_provider(
|
||||
custom_provider: Option<Box<dyn TopologyProvider>>,
|
||||
nym_api_urls: Vec<Url>,
|
||||
) -> Box<dyn TopologyProvider> {
|
||||
// if no custom provider was ... provided ..., create one using nym-api
|
||||
custom_provider.unwrap_or_else(|| {
|
||||
Box::new(NymApiTopologyProvider::new(
|
||||
nym_api_urls,
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
// future responsible for periodically polling directory server and updating
|
||||
// the current global view of topology
|
||||
async fn start_topology_refresher(
|
||||
topology_provider: Box<dyn TopologyProvider>,
|
||||
nym_api_urls: Vec<Url>,
|
||||
refresh_rate: Duration,
|
||||
topology_accessor: TopologyAccessor,
|
||||
shutdown: TaskClient,
|
||||
) -> Result<(), ClientCoreError> {
|
||||
let topology_refresher_config = TopologyRefresherConfig::new(refresh_rate);
|
||||
|
||||
let mut topology_refresher = TopologyRefresher::new(
|
||||
topology_refresher_config,
|
||||
topology_accessor,
|
||||
topology_provider,
|
||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||
nym_api_urls,
|
||||
refresh_rate,
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
);
|
||||
let mut topology_refresher =
|
||||
TopologyRefresher::new(topology_refresher_config, topology_accessor);
|
||||
// before returning, block entire runtime to refresh the current network view so that any
|
||||
// components depending on topology would see a non-empty view
|
||||
info!("Obtaining initial network topology");
|
||||
topology_refresher.try_refresh().await;
|
||||
topology_refresher.refresh().await;
|
||||
|
||||
if let Err(err) = topology_refresher.ensure_topology_is_routable().await {
|
||||
log::error!(
|
||||
@@ -493,12 +468,8 @@ where
|
||||
)
|
||||
.await?;
|
||||
|
||||
let topology_provider = Self::setup_topology_provider(
|
||||
self.custom_topology_provider.take(),
|
||||
self.nym_api_endpoints,
|
||||
);
|
||||
Self::start_topology_refresher(
|
||||
topology_provider,
|
||||
self.nym_api_endpoints.clone(),
|
||||
self.debug_config.topology_refresh_rate,
|
||||
shared_topology_accessor.clone(),
|
||||
task_manager.subscribe(),
|
||||
@@ -559,7 +530,7 @@ where
|
||||
self.debug_config,
|
||||
self.key_manager.ack_key(),
|
||||
self_address,
|
||||
shared_topology_accessor.clone(),
|
||||
shared_topology_accessor,
|
||||
sphinx_message_sender,
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
@@ -583,7 +554,6 @@ where
|
||||
client_state: ClientState {
|
||||
shared_lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
topology_accessor: shared_topology_accessor,
|
||||
},
|
||||
task_manager,
|
||||
})
|
||||
|
||||
@@ -155,21 +155,18 @@ impl Backend {
|
||||
// (assuming no key rotation has happened)
|
||||
// but the way it's currently coded, everyone will purge old data
|
||||
let since_last_flush = OffsetDateTime::now_utc() - last_flush;
|
||||
let days = since_last_flush.whole_days();
|
||||
let hours = since_last_flush.whole_hours() % 24;
|
||||
|
||||
if days > 0 {
|
||||
info!("it's been over {days} days and {hours} hours since we last used our data store. our reply surbs are already outdated - we're going to purge them now.");
|
||||
if since_last_flush.whole_days() > 0 {
|
||||
info!("it's been over {} days and {} hours since we last used our data store. our reply surbs are already outdated - we're going to purge them now.", since_last_flush.whole_days(), since_last_flush.whole_hours());
|
||||
manager.delete_all_reply_surb_data().await?;
|
||||
}
|
||||
|
||||
if days > 1 {
|
||||
info!("it's been over {days} days and {hours} hours since we last used our data store. our reply keys are already outdated - we're going to purge them now.");
|
||||
if since_last_flush.whole_days() > 1 {
|
||||
info!("it's been over {} days and {} hours since we last used our data store. our reply keys are already outdated - we're going to purge them now.", since_last_flush.whole_days(), since_last_flush.whole_hours());
|
||||
manager.delete_all_reply_keys().await?;
|
||||
}
|
||||
|
||||
if days > 2 {
|
||||
info!("it's been over {days} days and {hours} hours since we last used our data store. our used sender tags are already outdated - we're going to purge them now.");
|
||||
if since_last_flush.whole_days() > 2 {
|
||||
info!("it's been over {} days and {} hours since we last used our data store. our used sender tags are already outdated - we're going to purge them now.", since_last_flush.whole_days(), since_last_flush.whole_hours());
|
||||
manager.delete_all_tags().await?;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::spawn_future;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::DEFAULT_NUM_MIX_HOPS;
|
||||
use nym_topology::{nym_topology_from_detailed, NymTopology, NymTopologyError};
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||
use url::Url;
|
||||
|
||||
// I'm extremely curious why compiler NEVER complained about lack of Debug here before
|
||||
#[derive(Debug)]
|
||||
pub struct TopologyAccessorInner(Option<NymTopology>);
|
||||
|
||||
impl AsRef<Option<NymTopology>> for TopologyAccessorInner {
|
||||
fn as_ref(&self) -> &Option<NymTopology> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TopologyAccessorInner {
|
||||
fn new() -> Self {
|
||||
TopologyAccessorInner(None)
|
||||
}
|
||||
|
||||
fn update(&mut self, new: Option<NymTopology>) {
|
||||
self.0 = new;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyReadPermit<'a> {
|
||||
permit: RwLockReadGuard<'a, TopologyAccessorInner>,
|
||||
}
|
||||
|
||||
impl<'a> Deref for TopologyReadPermit<'a> {
|
||||
type Target = TopologyAccessorInner;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.permit
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TopologyReadPermit<'a> {
|
||||
/// Using provided topology read permit, tries to get an immutable reference to the underlying
|
||||
/// topology. For obvious reasons the lifetime of the topology reference is bound to the permit.
|
||||
pub(super) fn try_get_valid_topology_ref(
|
||||
&'a self,
|
||||
ack_recipient: &Recipient,
|
||||
packet_recipient: Option<&Recipient>,
|
||||
) -> Result<&'a NymTopology, NymTopologyError> {
|
||||
// 1. Have we managed to get anything from the refresher, i.e. have the nym-api queries gone through?
|
||||
let topology = self
|
||||
.permit
|
||||
.as_ref()
|
||||
.as_ref()
|
||||
.ok_or(NymTopologyError::EmptyNetworkTopology)?;
|
||||
|
||||
// 2. does it have any mixnode at all?
|
||||
// 3. does it have any gateways at all?
|
||||
// 4. does it have a mixnode on each layer?
|
||||
topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS)?;
|
||||
|
||||
// 5. does it contain OUR gateway (so that we could create an ack packet)?
|
||||
if !topology.gateway_exists(ack_recipient.gateway()) {
|
||||
return Err(NymTopologyError::NonExistentGatewayError {
|
||||
identity_key: ack_recipient.gateway().to_base58_string(),
|
||||
});
|
||||
}
|
||||
|
||||
// 6. for our target recipient, does it contain THEIR gateway (so that we could create
|
||||
if let Some(recipient) = packet_recipient {
|
||||
if !topology.gateway_exists(recipient.gateway()) {
|
||||
return Err(NymTopologyError::NonExistentGatewayError {
|
||||
identity_key: recipient.gateway().to_base58_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(topology)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<RwLockReadGuard<'a, TopologyAccessorInner>> for TopologyReadPermit<'a> {
|
||||
fn from(read_permit: RwLockReadGuard<'a, TopologyAccessorInner>) -> Self {
|
||||
TopologyReadPermit {
|
||||
permit: read_permit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TopologyAccessor {
|
||||
// `RwLock` *seems to* be the better approach for this as write access is only requested every
|
||||
// few seconds, while reads are needed every single packet generated.
|
||||
// However, proper benchmarks will be needed to determine if `RwLock` is indeed a better
|
||||
// approach than a `Mutex`
|
||||
inner: Arc<RwLock<TopologyAccessorInner>>,
|
||||
}
|
||||
|
||||
impl TopologyAccessor {
|
||||
pub fn new() -> Self {
|
||||
TopologyAccessor {
|
||||
inner: Arc::new(RwLock::new(TopologyAccessorInner::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_read_permit(&self) -> TopologyReadPermit<'_> {
|
||||
self.inner.read().await.into()
|
||||
}
|
||||
|
||||
async fn update_global_topology(&self, new_topology: Option<NymTopology>) {
|
||||
self.inner.write().await.update(new_topology);
|
||||
}
|
||||
|
||||
// only used by the client at startup to get a slightly more reasonable error message
|
||||
// (currently displays as unused because health checker is disabled due to required changes)
|
||||
pub async fn ensure_is_routable(&self) -> Result<(), NymTopologyError> {
|
||||
match &self.inner.read().await.0 {
|
||||
None => Err(NymTopologyError::EmptyNetworkTopology),
|
||||
Some(ref topology) => topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyAccessor {
|
||||
fn default() -> Self {
|
||||
TopologyAccessor::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyRefresherConfig {
|
||||
nym_api_urls: Vec<Url>,
|
||||
refresh_rate: Duration,
|
||||
client_version: String,
|
||||
}
|
||||
|
||||
impl TopologyRefresherConfig {
|
||||
pub fn new(nym_api_urls: Vec<Url>, refresh_rate: Duration, client_version: String) -> Self {
|
||||
TopologyRefresherConfig {
|
||||
nym_api_urls,
|
||||
refresh_rate,
|
||||
client_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyRefresher {
|
||||
validator_client: validator_client::client::NymApiClient,
|
||||
client_version: String,
|
||||
|
||||
nym_api_urls: Vec<Url>,
|
||||
topology_accessor: TopologyAccessor,
|
||||
refresh_rate: Duration,
|
||||
|
||||
currently_used_api: usize,
|
||||
was_latest_valid: bool,
|
||||
}
|
||||
|
||||
impl TopologyRefresher {
|
||||
pub fn new(mut cfg: TopologyRefresherConfig, topology_accessor: TopologyAccessor) -> Self {
|
||||
cfg.nym_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
TopologyRefresher {
|
||||
validator_client: validator_client::client::NymApiClient::new(
|
||||
cfg.nym_api_urls[0].clone(),
|
||||
),
|
||||
client_version: cfg.client_version,
|
||||
nym_api_urls: cfg.nym_api_urls,
|
||||
topology_accessor,
|
||||
refresh_rate: cfg.refresh_rate,
|
||||
currently_used_api: 0,
|
||||
was_latest_valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn use_next_nym_api(&mut self) {
|
||||
if self.nym_api_urls.len() == 1 {
|
||||
warn!("There's only a single nym API available - it won't be possible to use a different one");
|
||||
return;
|
||||
}
|
||||
|
||||
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
|
||||
self.validator_client
|
||||
.change_nym_api(self.nym_api_urls[self.currently_used_api].clone())
|
||||
}
|
||||
|
||||
/// Verifies whether nodes a reasonably distributed among all mix layers.
|
||||
///
|
||||
/// In ideal world we would have 33% nodes on layer 1, 33% on layer 2 and 33% on layer 3.
|
||||
/// However, this is a rather unrealistic expectation, instead we check whether there exists
|
||||
/// a layer with more than 66% of nodes or with fewer than 15% and if so, we trigger a failure.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `topology`: active topology constructed from validator api data
|
||||
fn check_layer_distribution(&self, active_topology: &NymTopology) -> bool {
|
||||
let mixes = active_topology.mixes();
|
||||
let mixnodes_count = active_topology.num_mixnodes();
|
||||
|
||||
if active_topology.gateways().is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// trivial check to see if have at least a single node on each layer (regardless of active set size)
|
||||
if mixes.get(&1).is_none() || mixes.get(&2).is_none() || mixes.get(&3).is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let upper_bound = (mixnodes_count as f32 * 0.66) as usize;
|
||||
let lower_bound = (mixnodes_count as f32 * 0.15) as usize;
|
||||
|
||||
let layer1 = mixes.get(&1).unwrap().len();
|
||||
let layer2 = mixes.get(&2).unwrap().len();
|
||||
let layer3 = mixes.get(&3).unwrap().len();
|
||||
|
||||
if layer1 < lower_bound || layer1 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if layer2 < lower_bound || layer2 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if layer3 < lower_bound || layer3 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
async fn get_current_compatible_topology(&self) -> Option<NymTopology> {
|
||||
// TODO: optimization for the future:
|
||||
// only refresh mixnodes on timer and refresh gateways only when
|
||||
// we have to send to a new, unknown, gateway
|
||||
|
||||
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network mixnodes - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(mixes) => mixes,
|
||||
};
|
||||
|
||||
let gateways = match self.validator_client.get_cached_gateways().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network gateways - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(gateways) => gateways,
|
||||
};
|
||||
|
||||
let topology = nym_topology_from_detailed(mixnodes, gateways)
|
||||
.filter_system_version(&self.client_version);
|
||||
|
||||
if !self.check_layer_distribution(&topology) {
|
||||
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used.");
|
||||
None
|
||||
} else {
|
||||
Some(topology)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn refresh(&mut self) {
|
||||
trace!("Refreshing the topology");
|
||||
let new_topology = self.get_current_compatible_topology().await;
|
||||
|
||||
if new_topology.is_none() {
|
||||
self.use_next_nym_api();
|
||||
}
|
||||
|
||||
if new_topology.is_none() && self.was_latest_valid {
|
||||
// if we failed to grab this topology, but the one before it was alright, let's assume
|
||||
// validator had a tiny hiccup and use the old data
|
||||
warn!("we're going to keep on using the old topology for this iteration");
|
||||
self.was_latest_valid = false;
|
||||
return;
|
||||
} else if new_topology.is_some() {
|
||||
self.was_latest_valid = true;
|
||||
}
|
||||
|
||||
self.topology_accessor
|
||||
.update_global_topology(new_topology)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn ensure_topology_is_routable(&self) -> Result<(), NymTopologyError> {
|
||||
self.topology_accessor.ensure_is_routable().await
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
|
||||
spawn_future(async move {
|
||||
debug!("Started TopologyRefresher with graceful shutdown support");
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let mut interval = tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(
|
||||
self.refresh_rate,
|
||||
));
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let mut interval =
|
||||
gloo_timers::future::IntervalStream::new(self.refresh_rate.as_millis() as u32);
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
_ = interval.next() => {
|
||||
self.refresh().await;
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
log::trace!("TopologyRefresher: Received shutdown");
|
||||
},
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
log::debug!("TopologyRefresher: Exiting");
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::DEFAULT_NUM_MIX_HOPS;
|
||||
use nym_topology::{NymTopology, NymTopologyError};
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{Notify, RwLock, RwLockReadGuard};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TopologyAccessorInner {
|
||||
controlled_manually: AtomicBool,
|
||||
released_manual_control: Notify,
|
||||
// `RwLock` *seems to* be the better approach for this as write access is only requested every
|
||||
// few seconds, while reads are needed every single packet generated.
|
||||
// However, proper benchmarks will be needed to determine if `RwLock` is indeed a better
|
||||
// approach than a `Mutex`
|
||||
topology: RwLock<Option<NymTopology>>,
|
||||
}
|
||||
|
||||
impl TopologyAccessorInner {
|
||||
fn new() -> Self {
|
||||
TopologyAccessorInner {
|
||||
controlled_manually: AtomicBool::new(false),
|
||||
released_manual_control: Notify::new(),
|
||||
topology: RwLock::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(&self, new: Option<NymTopology>) {
|
||||
*self.topology.write().await = new;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyReadPermit<'a> {
|
||||
permit: RwLockReadGuard<'a, Option<NymTopology>>,
|
||||
}
|
||||
|
||||
impl<'a> Deref for TopologyReadPermit<'a> {
|
||||
type Target = Option<NymTopology>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.permit
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TopologyReadPermit<'a> {
|
||||
/// Using provided topology read permit, tries to get an immutable reference to the underlying
|
||||
/// topology. For obvious reasons the lifetime of the topology reference is bound to the permit.
|
||||
pub(crate) fn try_get_valid_topology_ref(
|
||||
&'a self,
|
||||
ack_recipient: &Recipient,
|
||||
packet_recipient: Option<&Recipient>,
|
||||
) -> Result<&'a NymTopology, NymTopologyError> {
|
||||
// 1. Have we managed to get anything from the refresher, i.e. have the nym-api queries gone through?
|
||||
let topology = self
|
||||
.permit
|
||||
.as_ref()
|
||||
.ok_or(NymTopologyError::EmptyNetworkTopology)?;
|
||||
|
||||
// 2. does it have any mixnode at all?
|
||||
// 3. does it have any gateways at all?
|
||||
// 4. does it have a mixnode on each layer?
|
||||
topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS)?;
|
||||
|
||||
// 5. does it contain OUR gateway (so that we could create an ack packet)?
|
||||
if !topology.gateway_exists(ack_recipient.gateway()) {
|
||||
return Err(NymTopologyError::NonExistentGatewayError {
|
||||
identity_key: ack_recipient.gateway().to_base58_string(),
|
||||
});
|
||||
}
|
||||
|
||||
// 6. for our target recipient, does it contain THEIR gateway (so that we could create
|
||||
if let Some(recipient) = packet_recipient {
|
||||
if !topology.gateway_exists(recipient.gateway()) {
|
||||
return Err(NymTopologyError::NonExistentGatewayError {
|
||||
identity_key: recipient.gateway().to_base58_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(topology)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<RwLockReadGuard<'a, Option<NymTopology>>> for TopologyReadPermit<'a> {
|
||||
fn from(read_permit: RwLockReadGuard<'a, Option<NymTopology>>) -> Self {
|
||||
TopologyReadPermit {
|
||||
permit: read_permit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TopologyAccessor {
|
||||
inner: Arc<TopologyAccessorInner>,
|
||||
}
|
||||
|
||||
impl TopologyAccessor {
|
||||
pub fn new() -> Self {
|
||||
TopologyAccessor {
|
||||
inner: Arc::new(TopologyAccessorInner::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn controlled_manually(&self) -> bool {
|
||||
self.inner.controlled_manually.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub async fn get_read_permit(&self) -> TopologyReadPermit<'_> {
|
||||
self.inner.topology.read().await.into()
|
||||
}
|
||||
|
||||
pub(crate) async fn update_global_topology(&self, new_topology: Option<NymTopology>) {
|
||||
self.inner.update(new_topology).await;
|
||||
}
|
||||
|
||||
pub(crate) async fn wait_for_released_manual_control(&self) {
|
||||
self.inner.released_manual_control.notified().await
|
||||
}
|
||||
|
||||
pub async fn current_topology(&self) -> Option<NymTopology> {
|
||||
self.inner.topology.read().await.clone()
|
||||
}
|
||||
|
||||
pub async fn manually_change_topology(&self, new_topology: NymTopology) {
|
||||
self.inner.controlled_manually.store(true, Ordering::SeqCst);
|
||||
self.inner.update(Some(new_topology)).await;
|
||||
}
|
||||
|
||||
pub fn release_manual_control(&self) {
|
||||
self.inner
|
||||
.controlled_manually
|
||||
.store(false, Ordering::SeqCst);
|
||||
self.inner.released_manual_control.notify_waiters();
|
||||
}
|
||||
|
||||
// only used by the client at startup to get a slightly more reasonable error message
|
||||
// (currently displays as unused because health checker is disabled due to required changes)
|
||||
pub async fn ensure_is_routable(&self) -> Result<(), NymTopologyError> {
|
||||
match self.inner.topology.read().await.deref() {
|
||||
None => Err(NymTopologyError::EmptyNetworkTopology),
|
||||
Some(ref topology) => topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyAccessor {
|
||||
fn default() -> Self {
|
||||
TopologyAccessor::new()
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::spawn_future;
|
||||
pub(crate) use accessor::{TopologyAccessor, TopologyReadPermit};
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use nym_topology::NymTopologyError;
|
||||
use std::time::Duration;
|
||||
|
||||
mod accessor;
|
||||
pub(crate) mod nym_api_provider;
|
||||
|
||||
// TODO: move it to config later
|
||||
const MAX_FAILURE_COUNT: usize = 10;
|
||||
|
||||
pub struct TopologyRefresherConfig {
|
||||
refresh_rate: Duration,
|
||||
}
|
||||
|
||||
impl TopologyRefresherConfig {
|
||||
pub fn new(refresh_rate: Duration) -> Self {
|
||||
TopologyRefresherConfig { refresh_rate }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyRefresher {
|
||||
topology_provider: Box<dyn TopologyProvider>,
|
||||
topology_accessor: TopologyAccessor,
|
||||
|
||||
refresh_rate: Duration,
|
||||
consecutive_failure_count: usize,
|
||||
}
|
||||
|
||||
impl TopologyRefresher {
|
||||
pub fn new(
|
||||
cfg: TopologyRefresherConfig,
|
||||
topology_accessor: TopologyAccessor,
|
||||
topology_provider: Box<dyn TopologyProvider>,
|
||||
) -> Self {
|
||||
TopologyRefresher {
|
||||
topology_provider,
|
||||
topology_accessor,
|
||||
refresh_rate: cfg.refresh_rate,
|
||||
consecutive_failure_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_topology_provider(&mut self, provider: Box<dyn TopologyProvider>) {
|
||||
self.topology_provider = provider;
|
||||
}
|
||||
|
||||
pub async fn try_refresh(&mut self) {
|
||||
trace!("Refreshing the topology");
|
||||
|
||||
if self.topology_accessor.controlled_manually() {
|
||||
info!("topology is being controlled manually - we're going to wait until the control is released...");
|
||||
self.topology_accessor
|
||||
.wait_for_released_manual_control()
|
||||
.await;
|
||||
}
|
||||
|
||||
let new_topology = self.topology_provider.get_new_topology().await;
|
||||
if new_topology.is_none() {
|
||||
warn!("failed to obtain new network topology");
|
||||
}
|
||||
|
||||
if new_topology.is_none() && self.consecutive_failure_count < MAX_FAILURE_COUNT {
|
||||
// if we failed to grab this topology, but the one before it was alright, let's assume
|
||||
// validator had a tiny hiccup and use the old data
|
||||
warn!("we're going to keep on using the old topology for this iteration");
|
||||
self.consecutive_failure_count += 1;
|
||||
return;
|
||||
} else if new_topology.is_some() {
|
||||
self.consecutive_failure_count = 0;
|
||||
}
|
||||
|
||||
self.topology_accessor
|
||||
.update_global_topology(new_topology)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn ensure_topology_is_routable(&self) -> Result<(), NymTopologyError> {
|
||||
self.topology_accessor.ensure_is_routable().await
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
|
||||
spawn_future(async move {
|
||||
debug!("Started TopologyRefresher with graceful shutdown support");
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let mut interval = tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(
|
||||
self.refresh_rate,
|
||||
));
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let mut interval =
|
||||
gloo_timers::future::IntervalStream::new(self.refresh_rate.as_millis() as u32);
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
_ = interval.next() => {
|
||||
self.try_refresh().await;
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
log::trace!("TopologyRefresher: Received shutdown");
|
||||
},
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
log::debug!("TopologyRefresher: Exiting");
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use async_trait::async_trait;
|
||||
use log::{error, warn};
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use nym_topology::{nym_topology_from_detailed, NymTopology, NymTopologyError};
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use url::Url;
|
||||
|
||||
pub(crate) struct NymApiTopologyProvider {
|
||||
validator_client: validator_client::client::NymApiClient,
|
||||
nym_api_urls: Vec<Url>,
|
||||
|
||||
client_version: String,
|
||||
currently_used_api: usize,
|
||||
}
|
||||
|
||||
impl NymApiTopologyProvider {
|
||||
pub(crate) fn new(mut nym_api_urls: Vec<Url>, client_version: String) -> Self {
|
||||
nym_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
NymApiTopologyProvider {
|
||||
validator_client: validator_client::client::NymApiClient::new(nym_api_urls[0].clone()),
|
||||
nym_api_urls,
|
||||
client_version,
|
||||
currently_used_api: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn use_next_nym_api(&mut self) {
|
||||
if self.nym_api_urls.len() == 1 {
|
||||
warn!("There's only a single nym API available - it won't be possible to use a different one");
|
||||
return;
|
||||
}
|
||||
|
||||
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
|
||||
self.validator_client
|
||||
.change_nym_api(self.nym_api_urls[self.currently_used_api].clone())
|
||||
}
|
||||
|
||||
/// Verifies whether nodes a reasonably distributed among all mix layers.
|
||||
///
|
||||
/// In ideal world we would have 33% nodes on layer 1, 33% on layer 2 and 33% on layer 3.
|
||||
/// However, this is a rather unrealistic expectation, instead we check whether there exists
|
||||
/// a layer with more than 66% of nodes or with fewer than 15% and if so, we trigger a failure.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `topology`: active topology constructed from validator api data
|
||||
fn check_layer_distribution(
|
||||
&self,
|
||||
active_topology: &NymTopology,
|
||||
) -> Result<(), NymTopologyError> {
|
||||
let lower_threshold = 0.15;
|
||||
let upper_threshold = 0.66;
|
||||
active_topology.ensure_even_layer_distribution(lower_threshold, upper_threshold)
|
||||
}
|
||||
|
||||
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
|
||||
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network mixnodes - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(mixes) => mixes,
|
||||
};
|
||||
|
||||
let gateways = match self.validator_client.get_cached_gateways().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network gateways - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(gateways) => gateways,
|
||||
};
|
||||
|
||||
let topology = nym_topology_from_detailed(mixnodes, gateways)
|
||||
.filter_system_version(&self.client_version);
|
||||
|
||||
if let Err(err) = self.check_layer_distribution(&topology) {
|
||||
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}");
|
||||
self.use_next_nym_api();
|
||||
None
|
||||
} else {
|
||||
Some(topology)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hehe, wasm
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[async_trait]
|
||||
impl TopologyProvider for NymApiTopologyProvider {
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_current_compatible_topology().await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[async_trait(?Send)]
|
||||
impl TopologyProvider for NymApiTopologyProvider {
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_current_compatible_topology().await
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,10 @@ thiserror = "1.0"
|
||||
url = "2.2"
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
|
||||
|
||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||
coconut-interface = { path = "../../common/coconut-interface" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
credentials = { path = "../../common/credentials" }
|
||||
credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
|
||||
nym-bin-common = { path = "../../common/bin-common"}
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
|
||||
@@ -7,11 +7,11 @@ use nym_bin_common::completions::ArgShell;
|
||||
use rand::rngs::OsRng;
|
||||
use std::str::FromStr;
|
||||
|
||||
use nym_coconut_interface::{Base58, Parameters};
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credential_storage::PersistentStorage;
|
||||
use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||
use nym_credentials::coconut::utils::obtain_aggregate_signature;
|
||||
use coconut_interface::{Base58, Parameters};
|
||||
use credential_storage::storage::Storage;
|
||||
use credential_storage::PersistentStorage;
|
||||
use credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||
use credentials::coconut::utils::obtain_aggregate_signature;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_network_defaults::VOUCHER_INFO;
|
||||
use validator_client::nyxd::traits::DkgQueryClient;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
use std::time::SystemTimeError;
|
||||
use thiserror::Error;
|
||||
|
||||
use nym_credential_storage::error::StorageError;
|
||||
use nym_credentials::error::Error as CredentialError;
|
||||
use credential_storage::error::StorageError;
|
||||
use credentials::error::Error as CredentialError;
|
||||
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
|
||||
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||
use validator_client::nyxd::error::NyxdError;
|
||||
|
||||
@@ -77,7 +77,7 @@ async fn main() -> Result<()> {
|
||||
.client_home_directory
|
||||
.join(DATA_DIR)
|
||||
.join(CRED_DB_FILE_NAME);
|
||||
let shared_storage = nym_credential_storage::initialise_storage(db_path).await;
|
||||
let shared_storage = credential_storage::initialise_storage(db_path).await;
|
||||
let recovery_storage = recovery_storage::RecoveryStorage::new(r.recovery_dir)?;
|
||||
|
||||
let network_details = NymNetworkDetails::new_from_env();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
use credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
use std::fs::{create_dir_all, read_dir, File};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_coconut_interface::Parameters;
|
||||
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
use coconut_interface::Parameters;
|
||||
use credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.12"
|
||||
version = "1.1.11"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
@@ -36,10 +36,10 @@ tokio-tungstenite = "0.14" # websocket
|
||||
## internal
|
||||
nym-bin-common = { path = "../../common/bin-common" }
|
||||
client-core = { path = "../client-core", features = ["fs-surb-storage"] }
|
||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||
coconut-interface = { path = "../../common/coconut-interface" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
credential-storage = { path = "../../common/credential-storage" }
|
||||
credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
|
||||
@@ -74,7 +74,7 @@ impl SocketClient {
|
||||
let client = validator_client::Client::new_query(client_config)
|
||||
.expect("Could not construct query client");
|
||||
BandwidthController::new(
|
||||
nym_credential_storage::initialise_storage(config.get_base().get_database_path()).await,
|
||||
credential_storage::initialise_storage(config.get_base().get_database_path()).await,
|
||||
client,
|
||||
)
|
||||
}
|
||||
@@ -101,7 +101,6 @@ impl SocketClient {
|
||||
let ClientState {
|
||||
shared_lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
..
|
||||
} = client_state;
|
||||
|
||||
let websocket_handler = websocket::HandlerBuilder::new(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.12"
|
||||
version = "1.1.11"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
@@ -29,26 +29,26 @@ url = "2.2"
|
||||
# internal
|
||||
nym-bin-common = { path = "../../common/bin-common" }
|
||||
client-core = { path = "../client-core", features = ["fs-surb-storage"] }
|
||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||
coconut-interface = { path = "../../common/coconut-interface" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage", optional = true }
|
||||
credential-storage = { path = "../../common/credential-storage", optional = true }
|
||||
mobile-storage = { path = "../../common/mobile-storage", optional = true }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
||||
ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
nym-socks5-proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
|
||||
nym-service-providers-common = { path = "../../service-providers/common" }
|
||||
nym-socks5-requests = { path = "../../common/socks5/requests" }
|
||||
proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
|
||||
service-providers-common = { path = "../../service-providers/common" }
|
||||
socks5-requests = { path = "../../common/socks5/requests" }
|
||||
nym-task = { path = "../../common/task" }
|
||||
nym-topology = { path = "../../common/topology" }
|
||||
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||
|
||||
[features]
|
||||
default = ["nym-credential-storage"]
|
||||
default = ["credential-storage"]
|
||||
eth = []
|
||||
mobile = ["mobile-storage", "gateway-client/mobile"]
|
||||
|
||||
@@ -7,10 +7,10 @@ pub use client_core::config::MISSING_VALUE;
|
||||
use client_core::config::{ClientCoreConfigTrait, DebugConfig};
|
||||
use nym_config::defaults::DEFAULT_SOCKS5_LISTENING_PORT;
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use nym_service_providers_common::interface::ProviderInterfaceVersion;
|
||||
use nym_socks5_requests::Socks5ProtocolVersion;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use service_providers_common::interface::ProviderInterfaceVersion;
|
||||
use socks5_requests::Socks5ProtocolVersion;
|
||||
use std::fmt::Debug;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -92,7 +92,7 @@ impl NymClient {
|
||||
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
let storage =
|
||||
nym_credential_storage::initialise_storage(config.get_base().get_database_path()).await;
|
||||
credential_storage::initialise_storage(config.get_base().get_database_path()).await;
|
||||
|
||||
#[cfg(feature = "mobile")]
|
||||
let storage = mobile_storage::PersistentStorage {};
|
||||
@@ -123,7 +123,7 @@ impl NymClient {
|
||||
|
||||
let ClientState {
|
||||
shared_lane_queue_lengths,
|
||||
..
|
||||
reply_controller_sender: _,
|
||||
} = client_status;
|
||||
|
||||
let authenticator = Authenticator::new(auth_methods, allowed_users);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::socks::types::SocksProxyError;
|
||||
use client_core::error::ClientCoreError;
|
||||
use nym_socks5_requests::{ConnectionError, ConnectionId};
|
||||
use socks5_requests::{ConnectionError, ConnectionId};
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Socks5ClientError {
|
||||
|
||||
@@ -8,19 +8,19 @@ use client_core::client::inbound_messages::{InputMessage, InputMessageSender};
|
||||
use futures::channel::mpsc;
|
||||
use futures::task::{Context, Poll};
|
||||
use log::*;
|
||||
use nym_service_providers_common::interface::{ProviderInterfaceVersion, RequestVersion};
|
||||
use nym_socks5_proxy_helpers::connection_controller::{
|
||||
ConnectionReceiver, ControllerCommand, ControllerSender,
|
||||
};
|
||||
use nym_socks5_proxy_helpers::proxy_runner::ProxyRunner;
|
||||
use nym_socks5_requests::{
|
||||
ConnectionId, RemoteAddress, Socks5ProtocolVersion, Socks5ProviderRequest, Socks5Request,
|
||||
};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_task::connections::{LaneQueueLengths, TransmissionLane};
|
||||
use nym_task::TaskClient;
|
||||
use pin_project::pin_project;
|
||||
use proxy_helpers::connection_controller::{
|
||||
ConnectionReceiver, ControllerCommand, ControllerSender,
|
||||
};
|
||||
use proxy_helpers::proxy_runner::ProxyRunner;
|
||||
use rand::RngCore;
|
||||
use service_providers_common::interface::{ProviderInterfaceVersion, RequestVersion};
|
||||
use socks5_requests::{
|
||||
ConnectionId, RemoteAddress, Socks5ProtocolVersion, Socks5ProviderRequest, Socks5Request,
|
||||
};
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
|
||||
@@ -4,11 +4,11 @@ use log::*;
|
||||
|
||||
use client_core::client::received_buffer::ReconstructedMessagesReceiver;
|
||||
use client_core::client::received_buffer::{ReceivedBufferMessage, ReceivedBufferRequestSender};
|
||||
use nym_service_providers_common::interface::{ControlResponse, ResponseContent};
|
||||
use nym_socks5_proxy_helpers::connection_controller::ControllerSender;
|
||||
use nym_socks5_requests::{Socks5ProviderResponse, Socks5Response, Socks5ResponseContent};
|
||||
use nym_sphinx::receiver::ReconstructedMessage;
|
||||
use nym_task::TaskClient;
|
||||
use proxy_helpers::connection_controller::ControllerSender;
|
||||
use service_providers_common::interface::{ControlResponse, ResponseContent};
|
||||
use socks5_requests::{Socks5ProviderResponse, Socks5Response, Socks5ResponseContent};
|
||||
|
||||
use crate::error::Socks5ClientError;
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@ use client_core::client::{
|
||||
inbound_messages::InputMessageSender, received_buffer::ReceivedBufferRequestSender,
|
||||
};
|
||||
use log::*;
|
||||
use nym_socks5_proxy_helpers::connection_controller::Controller;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_task::connections::{ConnectionCommandSender, LaneQueueLengths};
|
||||
use nym_task::TaskClient;
|
||||
use proxy_helpers::connection_controller::Controller;
|
||||
use std::net::SocketAddr;
|
||||
use tap::TapFallible;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use nym_socks5_requests::Socks5RequestError;
|
||||
use socks5_requests::Socks5RequestError;
|
||||
use std::string::FromUtf8Error;
|
||||
use thiserror::Error;
|
||||
|
||||
|
||||
@@ -1,71 +1,83 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2019,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"globals": {
|
||||
"Atomics": "readonly",
|
||||
"SharedArrayBuffer": "readonly"
|
||||
},
|
||||
"plugins": ["prettier", "mocha"],
|
||||
"extends": ["airbnb-base", "airbnb-typescript/base", "prettier"],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"import/prefer-default-export": "off",
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": ["**/*.test.[jt]s", "**/*.spec.[jt]s"]
|
||||
}
|
||||
],
|
||||
"import/extensions": [
|
||||
"error",
|
||||
"ignorePackages",
|
||||
{
|
||||
"ts": "never",
|
||||
"js": "never"
|
||||
}
|
||||
]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": "**/*.ts",
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"plugins": ["@typescript-eslint/eslint-plugin"],
|
||||
"extends": ["plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended", "prettier"],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"no-use-before-define": [0],
|
||||
"@typescript-eslint/no-use-before-define": [1],
|
||||
"import/no-unresolved": 0,
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2019,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"globals": {
|
||||
"Atomics": "readonly",
|
||||
"SharedArrayBuffer": "readonly"
|
||||
},
|
||||
"plugins": ["prettier", "mocha"],
|
||||
"extends": [
|
||||
"airbnb-base",
|
||||
"airbnb-typescript/base",
|
||||
"prettier"],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"import/prefer-default-export": "off",
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": ["**/*.test.ts", "**/*.spec.ts"]
|
||||
}
|
||||
"error",
|
||||
{
|
||||
"devDependencies": [
|
||||
"**/*.test.[jt]s",
|
||||
"**/*.spec.[jt]s"
|
||||
]
|
||||
}
|
||||
],
|
||||
"quotes": "off",
|
||||
"@typescript-eslint/quotes": [
|
||||
2,
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-unused-vars": [2, { "argsIgnorePattern": "^_" }]
|
||||
}
|
||||
}
|
||||
],
|
||||
"ignorePatterns": ["tsconfig.json", "*.d.ts", "dist/**/*", "dist", "node_modules"]
|
||||
"import/extensions": [
|
||||
"error",
|
||||
"ignorePackages",
|
||||
{
|
||||
"ts": "never",
|
||||
"js": "never"
|
||||
}
|
||||
]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": "**/*.ts",
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"plugins": ["@typescript-eslint/eslint-plugin"],
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"no-use-before-define": [0],
|
||||
"@typescript-eslint/no-use-before-define": [1],
|
||||
"import/no-unresolved": 0,
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": [
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
],
|
||||
"quotes": "off",
|
||||
"@typescript-eslint/quotes": [
|
||||
2,
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-unused-vars": [2, { "argsIgnorePattern": "^_" }]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,5 +4,4 @@ coverage
|
||||
dist
|
||||
docs
|
||||
examples/accounts
|
||||
node_modules
|
||||
.env
|
||||
node_modules
|
||||
@@ -1,5 +1,3 @@
|
||||
coverage
|
||||
node_modules
|
||||
tests
|
||||
src
|
||||
type
|
||||
tests
|
||||
+25
-24
@@ -1,39 +1,40 @@
|
||||
# Nym Validator Client (Typescript)
|
||||
Nym Validator Client
|
||||
====================
|
||||
|
||||
A TypeScript client for interacting with CosmWasm smart contracts in Nym validators.
|
||||
A TypeScript client for interacting with CosmWasm smart contracts in Nym validators.
|
||||
|
||||
Include the Nym Validator in your project:
|
||||
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
|
||||
-------------
|
||||
|
||||
```
|
||||
yarn add @nymproject/nym-validator-client
|
||||
npm test
|
||||
```
|
||||
|
||||
Connect to validator and make queries
|
||||
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:
|
||||
|
||||
|
||||
```
|
||||
import Validator from '@nymproject/nym-validator-client'
|
||||
|
||||
const main = async () => {
|
||||
|
||||
const client = await Validator.connectForQuery(rpcAddress, validatorAddress, prefix, mixnetContractAddress, vestingContractAddress, denom)
|
||||
|
||||
client.getBalance(address)
|
||||
|
||||
}
|
||||
|
||||
cargo watch -s "cd clients/validator && npm test"
|
||||
```
|
||||
|
||||
Connect to validator for performing actions
|
||||
It's ugly but works fine if you have Cargo installed. TypeScript setup help happily accepted here.
|
||||
|
||||
```
|
||||
import Validator from '@nymproject/nym-validator-client'
|
||||
Generating Documentation
|
||||
------------------------
|
||||
|
||||
const main = async () => {
|
||||
You can generate docs by running `npm run docs`. Generated output will appear in the `docs` directory.
|
||||
|
||||
const client = await Validator.connect(mnemonic, rpcAddress, validatorAddress, prefix, mixnetContractAddress, vestingContractAddress, denom)
|
||||
Packaging
|
||||
------------------------
|
||||
|
||||
const res = await client.send(address, [{ amount: '10000000', denom: 'unym' }]);
|
||||
If you're a Nym platform developer who's made changes to the client and wants to re-publish the package to NPM, here's how you do it:
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
1. Bump the version number (use SemVer)
|
||||
1. `npm run build`
|
||||
1. `npm login` (if you haven't already)
|
||||
1. `npm publish`
|
||||
@@ -4,23 +4,15 @@
|
||||
"description": "A TypeScript client for interacting with smart contracts in Nym validators",
|
||||
"repository": "https://github.com/nymtech/nym",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "rollup -c ./rollup.config.mjs",
|
||||
"build:types": "rollup-type-bundler --dist ./dist/nym-validator-client",
|
||||
"build:prod": "sh ./scripts/build-prod.sh",
|
||||
"test": "ts-mocha -p ./tsconfig.test.json ./src/tests/**/*.test.ts",
|
||||
"testmock": "ts-mocha -p ./tsconfig.test.json ./src/tests/mock/*.test.ts",
|
||||
"build": "tsc",
|
||||
"test": "ts-mocha tests/**/*.test.ts",
|
||||
"coverage": "nyc npm test",
|
||||
"clean": "rm -rf ./dist",
|
||||
"lint": "eslint",
|
||||
"lint:fix": "eslint --fix",
|
||||
"lint:tsc": "tsc --noEmit",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"docs": "typedoc --out docs src/index.ts"
|
||||
},
|
||||
"files": [
|
||||
"./dist/*"
|
||||
],
|
||||
"keywords": [],
|
||||
"author": "Nym Technologies SA (https://nymtech.net)",
|
||||
"contributors": [
|
||||
@@ -29,14 +21,6 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@favware/rollup-type-bundler": "^2.0.0",
|
||||
"@nymproject/types": "^1.0.0",
|
||||
"@rollup/plugin-commonjs": "^24.0.1",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"rollup": "^3.17.2",
|
||||
"rollup-plugin-dts": "^5.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
||||
"@typescript-eslint/parser": "^5.7.0",
|
||||
"eslint": "^7.18.0",
|
||||
@@ -47,21 +31,21 @@
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-mocha": "^10.0.3",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"expect": "^28.1.3",
|
||||
"mocha": "^10.0.0",
|
||||
"prettier": "^2.5.1",
|
||||
"ts-mocha": "^10.0.0",
|
||||
"typedoc": "^0.22.13",
|
||||
"typescript": "^4.6.2",
|
||||
"cosmjs-types": "^0.4.1",
|
||||
"dotenv": "^16.0.3",
|
||||
"expect": "^28.1.3",
|
||||
"moq.ts": "^7.3.4",
|
||||
"@cosmjs/cosmwasm-stargate": "^0.29.5",
|
||||
"@cosmjs/crypto": "^0.29.5",
|
||||
"@cosmjs/math": "^0.29.5",
|
||||
"@cosmjs/proto-signing": "^0.29.5",
|
||||
"@cosmjs/stargate": "^0.29.5",
|
||||
"@cosmjs/tendermint-rpc": "^0.29.5",
|
||||
"axios": "^1.3.3"
|
||||
"ts-mocha": "^10.0.0",
|
||||
"typescript": "^4.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cosmjs/cosmwasm-stargate": "^0.28.0",
|
||||
"@cosmjs/crypto": "^0.28.0",
|
||||
"@cosmjs/math": "^0.28.0",
|
||||
"@cosmjs/proto-signing": "^0.28.0",
|
||||
"@cosmjs/stargate": "^0.28.0",
|
||||
"@cosmjs/tendermint-rpc": "^0.28.0",
|
||||
"axios": "^0.26.1",
|
||||
"cosmjs-types": "^0.4.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import json from '@rollup/plugin-json';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
|
||||
export default [
|
||||
{
|
||||
input: './src/index.ts',
|
||||
output: {
|
||||
dir: 'dist/nym-validator-client',
|
||||
format: 'cjs',
|
||||
},
|
||||
plugins: [resolve(), typescript(), commonjs(), json()],
|
||||
},
|
||||
];
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
|
||||
rm -rf ./dist || true
|
||||
rm -rf ../../dist || true
|
||||
|
||||
|
||||
# Bundle application
|
||||
|
||||
yarn build
|
||||
|
||||
# Bundle types
|
||||
|
||||
yarn build:types
|
||||
|
||||
# Build package.json for bundle
|
||||
|
||||
node ./scripts/buildPackageJson.mjs
|
||||
|
||||
# Copy README
|
||||
|
||||
cp README.md dist/nym-validator-client
|
||||
|
||||
# move the output outside of the yarn/npm workspaces
|
||||
|
||||
mv ./dist ../../
|
||||
|
||||
echo "Output can be found in:"
|
||||
realpath ../../dist
|
||||
@@ -1,20 +0,0 @@
|
||||
import * as fs from 'fs';
|
||||
|
||||
// parse the package.json from the SDK, so we can keep fields like the name and version
|
||||
const json = JSON.parse(fs.readFileSync('./package.json').toString());
|
||||
|
||||
// defaults (NB: these are in the output file locations)
|
||||
const main = 'index.js';
|
||||
const types = 'index.d.ts';
|
||||
|
||||
// make a package.json for the bundle
|
||||
const packageJson = {
|
||||
name: json.name,
|
||||
version: json.version,
|
||||
license: json.license,
|
||||
author: json.author,
|
||||
main,
|
||||
types,
|
||||
};
|
||||
|
||||
fs.writeFileSync('./dist/nym-validator-client/package.json', JSON.stringify(packageJson, null, 2));
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Decimal } from '@cosmjs/math';
|
||||
import { Coin } from '@cosmjs/stargate';
|
||||
import { CoinMap } from './types/shared';
|
||||
|
||||
// NARROW NO-BREAK SPACE (U+202F)
|
||||
const thinSpace = '\u202F';
|
||||
@@ -35,6 +34,15 @@ export function nativeToPrintable(nativeValue: string): string {
|
||||
return Decimal.fromAtomics(nativeValue, 6).toString();
|
||||
}
|
||||
|
||||
export interface MappedCoin {
|
||||
readonly denom: string;
|
||||
readonly fractionalDigits: number;
|
||||
}
|
||||
|
||||
export interface CoinMap {
|
||||
readonly [key: string]: MappedCoin;
|
||||
}
|
||||
|
||||
export function nativeCoinToDisplay(coin: Coin, coinMap: CoinMap): Coin {
|
||||
if (!coinMap) return coin;
|
||||
|
||||
|
||||
+75
-133
@@ -1,3 +1,6 @@
|
||||
import { Bip39, Random } from '@cosmjs/crypto';
|
||||
import { DirectSecp256k1HdWallet, EncodeObject } from '@cosmjs/proto-signing';
|
||||
import { coin as cosmosCoin, Coin, DeliverTxResponse, isDeliverTxFailure, StdFee } from '@cosmjs/stargate';
|
||||
import {
|
||||
ExecuteResult,
|
||||
InstantiateOptions,
|
||||
@@ -5,37 +8,45 @@ import {
|
||||
MigrateResult,
|
||||
UploadResult,
|
||||
} from '@cosmjs/cosmwasm-stargate';
|
||||
import { Bip39, Random } from '@cosmjs/crypto';
|
||||
import { DirectSecp256k1HdWallet, EncodeObject } from '@cosmjs/proto-signing';
|
||||
import { Coin, coin as cosmosCoin, DeliverTxResponse, isDeliverTxFailure, StdFee } from '@cosmjs/stargate';
|
||||
import SigningClient, { ISigningClient } from './signing-client';
|
||||
import {
|
||||
ContractStateParams,
|
||||
Delegation,
|
||||
Gateway,
|
||||
GatewayBond,
|
||||
GatewayOwnershipResponse,
|
||||
LayerDistribution,
|
||||
MixnetContractVersion,
|
||||
MixNode,
|
||||
MixNodeBond,
|
||||
MixNodeCostParams,
|
||||
MixNodeDetails,
|
||||
MixNodeRewarding,
|
||||
MixOwnershipResponse,
|
||||
PagedAllDelegationsResponse,
|
||||
PagedDelegatorDelegationsResponse,
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixNodeBondResponse,
|
||||
PagedMixNodeDetailsResponse,
|
||||
PagedUnbondedMixnodesResponse,
|
||||
RewardingParams,
|
||||
StakeSaturationResponse,
|
||||
UnbondedMixnodeResponse,
|
||||
} from '@nymproject/types';
|
||||
PagedMixnodeResponse,
|
||||
} from './types';
|
||||
import {
|
||||
CoinMap,
|
||||
displayAmountToNative,
|
||||
MappedCoin,
|
||||
nativeCoinToDisplay,
|
||||
nativeToPrintable,
|
||||
printableBalance,
|
||||
printableCoin,
|
||||
} from './currency';
|
||||
import QueryClient from './query-client';
|
||||
import SigningClient, { ISigningClient } from './signing-client';
|
||||
import { ContractState } from './types/shared';
|
||||
import { nymGasPrice } from './stargate-helper';
|
||||
|
||||
export { coins, coin } from '@cosmjs/stargate';
|
||||
export { Coin };
|
||||
export {
|
||||
displayAmountToNative,
|
||||
nativeCoinToDisplay,
|
||||
printableCoin,
|
||||
printableBalance,
|
||||
nativeToPrintable,
|
||||
MappedCoin,
|
||||
CoinMap,
|
||||
};
|
||||
export { nymGasPrice };
|
||||
|
||||
export interface INymClient {
|
||||
readonly mixnetContract: string;
|
||||
@@ -136,7 +147,7 @@ export default class ValidatorClient implements INymClient {
|
||||
return DirectSecp256k1HdWallet.fromMnemonic(mnemonic, signerOptions);
|
||||
}
|
||||
|
||||
async getBalance(address: string): Promise<Coin> {
|
||||
getBalance(address: string): Promise<Coin> {
|
||||
return this.client.getBalance(address, this.denom);
|
||||
}
|
||||
|
||||
@@ -148,39 +159,15 @@ export default class ValidatorClient implements INymClient {
|
||||
return this.client.getCachedMixnodes();
|
||||
}
|
||||
|
||||
async getStakeSaturation(mixId: number): Promise<StakeSaturationResponse> {
|
||||
return this.client.getStakeSaturation(this.mixnetContract, mixId);
|
||||
}
|
||||
|
||||
async getActiveMixnodes(): Promise<MixNodeDetails[]> {
|
||||
async getActiveMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.client.getActiveMixnodes();
|
||||
}
|
||||
|
||||
async getUnbondedMixNodeInformation(mixId: number): Promise<UnbondedMixnodeResponse> {
|
||||
return this.client.getUnbondedMixNodeInformation(this.mixnetContract, mixId);
|
||||
}
|
||||
|
||||
async getRewardedMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.client.getRewardedMixnodes();
|
||||
}
|
||||
|
||||
async getMixnodeRewardingDetails(mixId: number): Promise<MixNodeRewarding> {
|
||||
return this.client.getMixnodeRewardingDetails(this.mixnetContract, mixId);
|
||||
}
|
||||
|
||||
async getOwnedMixnode(address: string): Promise<MixOwnershipResponse> {
|
||||
return this.client.getOwnedMixnode(this.mixnetContract, address);
|
||||
}
|
||||
|
||||
async ownsGateway(address: string): Promise<GatewayOwnershipResponse> {
|
||||
return this.client.ownsGateway(this.mixnetContract, address);
|
||||
}
|
||||
|
||||
async getLayerDistribution(): Promise<LayerDistribution> {
|
||||
return this.client.getLayerDistribution(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getMixnetContractSettings(): Promise<ContractState> {
|
||||
public async getMixnetContractSettings(): Promise<ContractStateParams> {
|
||||
return this.client.getStateParams(this.mixnetContract);
|
||||
}
|
||||
|
||||
@@ -188,74 +175,29 @@ export default class ValidatorClient implements INymClient {
|
||||
return this.client.getContractVersion(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getVestingContractVersion(): Promise<MixnetContractVersion> {
|
||||
return this.client.getContractVersion(this.vestingContract);
|
||||
public async getRewardPool(): Promise<string> {
|
||||
return this.client.getRewardPool(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getSpendableCoins(vestingAccountAddress: string): Promise<MixnetContractVersion> {
|
||||
return this.client.getSpendableCoins(this.vestingContract, vestingAccountAddress);
|
||||
public async getCirculatingSupply(): Promise<string> {
|
||||
return this.client.getCirculatingSupply(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getRewardParams(): Promise<RewardingParams> {
|
||||
return this.client.getRewardParams(this.mixnetContract);
|
||||
public async getSybilResistancePercent(): Promise<number> {
|
||||
return this.client.getSybilResistancePercent(this.mixnetContract);
|
||||
}
|
||||
|
||||
async getUnbondedMixNodes(): Promise<UnbondedMixnodeResponse[]> {
|
||||
let mixNodes: UnbondedMixnodeResponse[] = [];
|
||||
const limit = 50;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedUnbondedMixnodesResponse = await this.client.getUnbondedMixNodes(
|
||||
this.mixnetContract,
|
||||
limit,
|
||||
startAfter,
|
||||
);
|
||||
|
||||
mixNodes = mixNodes.concat(pagedResponse.nodes);
|
||||
startAfter = pagedResponse.start_next_after;
|
||||
// if `start_next_after` is not set, we're done
|
||||
if (!startAfter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mixNodes;
|
||||
public async getIntervalRewardPercent(): Promise<number> {
|
||||
return this.client.getIntervalRewardPercent(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getMixNodeBonds(): Promise<MixNodeBond[]> {
|
||||
public async getAllNyxdMixnodes(): Promise<MixNodeBond[]> {
|
||||
let mixNodes: MixNodeBond[] = [];
|
||||
const limit = 50;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedMixNodeBondResponse = await this.client.getMixNodeBonds(
|
||||
this.mixnetContract,
|
||||
limit,
|
||||
startAfter,
|
||||
);
|
||||
mixNodes = mixNodes.concat(pagedResponse.nodes);
|
||||
startAfter = pagedResponse.start_next_after;
|
||||
// if `start_next_after` is not set, we're done
|
||||
if (!startAfter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mixNodes;
|
||||
}
|
||||
|
||||
public async getMixNodesDetailed(): Promise<MixNodeDetails[]> {
|
||||
let mixNodes: MixNodeDetails[] = [];
|
||||
const limit = 50;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedMixNodeDetailsResponse = await this.client.getMixNodesDetailed(
|
||||
this.mixnetContract,
|
||||
limit,
|
||||
startAfter,
|
||||
);
|
||||
const pagedResponse: PagedMixnodeResponse = await this.client.getMixNodesPaged(this.mixnetContract, limit);
|
||||
mixNodes = mixNodes.concat(pagedResponse.nodes);
|
||||
startAfter = pagedResponse.start_next_after;
|
||||
// if `start_next_after` is not set, we're done
|
||||
@@ -268,24 +210,37 @@ export default class ValidatorClient implements INymClient {
|
||||
}
|
||||
|
||||
public async getAllNyxdGateways(): Promise<GatewayBond[]> {
|
||||
const pagedResponse: PagedGatewayResponse = await this.client.getGatewaysPaged(this.mixnetContract);
|
||||
return pagedResponse.nodes;
|
||||
let gateways: GatewayBond[] = [];
|
||||
const limit = 50;
|
||||
let startAfter;
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedGatewayResponse = await this.client.getGatewaysPaged(this.mixnetContract, limit);
|
||||
gateways = gateways.concat(pagedResponse.nodes);
|
||||
startAfter = pagedResponse.start_next_after;
|
||||
// if `start_next_after` is not set, we're done
|
||||
if (!startAfter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return gateways;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list of all delegations towards particular mixnode.
|
||||
*
|
||||
* @param mix_id identity of the node to which the delegation was sent
|
||||
* @param mixIdentity identity of the node to which the delegation was sent
|
||||
*/
|
||||
public async getAllNyxdSingleMixnodeDelegations(mix_id: number): Promise<Delegation[]> {
|
||||
public async getAllNyxdSingleMixnodeDelegations(mixIdentity: string): Promise<Delegation[]> {
|
||||
let delegations: Delegation[] = [];
|
||||
const limit = 250;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedMixDelegationsResponse = await this.client.getMixNodeDelegationsPaged(
|
||||
this.mixnetContract,
|
||||
mix_id,
|
||||
mixIdentity,
|
||||
limit,
|
||||
startAfter,
|
||||
);
|
||||
@@ -304,7 +259,7 @@ export default class ValidatorClient implements INymClient {
|
||||
let delegations: Delegation[] = [];
|
||||
const limit = 250;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedDelegatorDelegationsResponse = await this.client.getDelegatorDelegationsPaged(
|
||||
this.mixnetContract,
|
||||
@@ -323,13 +278,13 @@ export default class ValidatorClient implements INymClient {
|
||||
return delegations;
|
||||
}
|
||||
|
||||
public async getAllNyxdDelegations(): Promise<Delegation[]> {
|
||||
public async getAllNyxdNetworkDelegations(): Promise<Delegation[]> {
|
||||
let delegations: Delegation[] = [];
|
||||
const limit = 250;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedAllDelegationsResponse = await this.client.getAllDelegationsPaged(
|
||||
const pagedResponse: PagedAllDelegationsResponse = await this.client.getAllNetworkDelegationsPaged(
|
||||
this.mixnetContract,
|
||||
limit,
|
||||
startAfter,
|
||||
@@ -345,10 +300,6 @@ export default class ValidatorClient implements INymClient {
|
||||
return delegations;
|
||||
}
|
||||
|
||||
public async getDelegationDetails(mix_id: number, delegator: string): Promise<Delegation> {
|
||||
return this.client.getDelegationDetails(this.mixnetContract, mix_id, delegator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a minimum gateway bond required to create a fresh mixnode.
|
||||
*
|
||||
@@ -357,7 +308,7 @@ export default class ValidatorClient implements INymClient {
|
||||
public async minimumMixnodePledge(): Promise<Coin> {
|
||||
const stateParams = await this.getMixnetContractSettings();
|
||||
// we trust the contract to return a valid number
|
||||
return cosmosCoin(stateParams.params.minimum_mixnode_pledge, this.prefix);
|
||||
return cosmosCoin(stateParams.minimum_mixnode_pledge, this.prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,7 +319,7 @@ export default class ValidatorClient implements INymClient {
|
||||
public async minimumGatewayPledge(): Promise<Coin> {
|
||||
const stateParams = await this.getMixnetContractSettings();
|
||||
// we trust the contract to return a valid number
|
||||
return cosmosCoin(stateParams.params.minimum_gateway_pledge, this.prefix);
|
||||
return cosmosCoin(stateParams.minimum_gateway_pledge, this.prefix);
|
||||
}
|
||||
|
||||
public async send(
|
||||
@@ -442,21 +393,12 @@ export default class ValidatorClient implements INymClient {
|
||||
public async bondMixNode(
|
||||
mixNode: MixNode,
|
||||
ownerSignature: string,
|
||||
costParams: MixNodeCostParams,
|
||||
pledge: Coin,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
memo?: string,
|
||||
): Promise<ExecuteResult> {
|
||||
this.assertSigning();
|
||||
return (this.client as ISigningClient).bondMixNode(
|
||||
this.mixnetContract,
|
||||
mixNode,
|
||||
costParams,
|
||||
ownerSignature,
|
||||
pledge,
|
||||
fee,
|
||||
memo,
|
||||
);
|
||||
return (this.client as ISigningClient).bondMixNode(this.mixnetContract, mixNode, ownerSignature, pledge, fee, memo);
|
||||
}
|
||||
|
||||
public async unbondMixNode(fee?: StdFee | 'auto' | number, memo?: string): Promise<ExecuteResult> {
|
||||
@@ -481,29 +423,29 @@ export default class ValidatorClient implements INymClient {
|
||||
}
|
||||
|
||||
public async delegateToMixNode(
|
||||
mixId: number,
|
||||
mixIdentity: string,
|
||||
amount: Coin,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
memo?: string,
|
||||
): Promise<ExecuteResult> {
|
||||
this.assertSigning();
|
||||
return (this.client as ISigningClient).delegateToMixNode(this.mixnetContract, mixId, amount, fee, memo);
|
||||
return (this.client as ISigningClient).delegateToMixNode(this.mixnetContract, mixIdentity, amount, fee, memo);
|
||||
}
|
||||
|
||||
public async undelegateFromMixNode(
|
||||
mixId: number,
|
||||
mixIdentity: string,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
memo?: string,
|
||||
): Promise<ExecuteResult> {
|
||||
return (this.client as ISigningClient).undelegateFromMixNode(this.mixnetContract, mixId, fee, memo);
|
||||
return (this.client as ISigningClient).undelegateFromMixNode(this.mixnetContract, mixIdentity, fee, memo);
|
||||
}
|
||||
|
||||
public async updateMixnodeConfig(
|
||||
mixId: number,
|
||||
mixIdentity: string,
|
||||
fee: StdFee | 'auto' | number,
|
||||
profitPercentage: number,
|
||||
): Promise<ExecuteResult> {
|
||||
return (this.client as ISigningClient).updateMixnodeConfig(this.mixnetContract, mixId, profitPercentage, fee);
|
||||
return (this.client as ISigningClient).updateMixnodeConfig(this.mixnetContract, mixIdentity, profitPercentage, fee);
|
||||
}
|
||||
|
||||
public async updateContractStateParams(
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
* Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
import { GatewayBond, MixNodeBond, MixNodeDetails } from '@nymproject/types';
|
||||
import { GatewayBond, MixNodeBond } from './types';
|
||||
|
||||
export const NYM_API_VERSION = '/v1';
|
||||
export const NYM_API_GATEWAYS_PATH = `${NYM_API_VERSION}/gateways`;
|
||||
@@ -16,7 +17,7 @@ export interface INymApiQuery {
|
||||
|
||||
getCachedGateways(): Promise<GatewayBond[]>;
|
||||
|
||||
getActiveMixnodes(): Promise<MixNodeDetails[]>;
|
||||
getActiveMixnodes(): Promise<MixNodeBond[]>;
|
||||
|
||||
getRewardedMixnodes(): Promise<MixNodeBond[]>;
|
||||
}
|
||||
@@ -50,7 +51,7 @@ export default class NymApiQuerier implements INymApiQuery {
|
||||
throw new Error('None of the provided validator APIs seem to be alive');
|
||||
}
|
||||
|
||||
async getActiveMixnodes(): Promise<MixNodeDetails[]> {
|
||||
async getActiveMixnodes(): Promise<MixNodeBond[]> {
|
||||
const url = new URL(this.nymApiUrl);
|
||||
url.pathname += NYM_API_ACTIVE_MIXNODES_PATH;
|
||||
|
||||
|
||||
@@ -2,24 +2,28 @@
|
||||
* Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { JsonObject } from '@cosmjs/cosmwasm-stargate';
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import { INyxdQuery } from './query-client';
|
||||
import { Delegation, RewardingParams, StakeSaturationResponse } from '@nymproject/types';
|
||||
import {
|
||||
UnbondedMixnodeResponse,
|
||||
ContractStateParams,
|
||||
Delegation,
|
||||
GatewayOwnershipResponse,
|
||||
LayerDistribution,
|
||||
MixnetContractVersion,
|
||||
MixOwnershipResponse,
|
||||
PagedAllDelegationsResponse,
|
||||
PagedDelegatorDelegationsResponse,
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixNodeBondResponse,
|
||||
PagedMixNodeDetailsResponse,
|
||||
PagedUnbondedMixnodesResponse,
|
||||
LayerDistribution,
|
||||
} from '@nymproject/types';
|
||||
import { ContractState, SmartContractQuery } from './types/shared';
|
||||
PagedMixnodeResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
|
||||
interface SmartContractQuery {
|
||||
queryContractSmart(address: string, queryMsg: Record<string, unknown>): Promise<JsonObject>;
|
||||
}
|
||||
|
||||
export default class NyxdQuerier implements INyxdQuery {
|
||||
client: SmartContractQuery;
|
||||
@@ -34,44 +38,15 @@ export default class NyxdQuerier implements INyxdQuery {
|
||||
});
|
||||
}
|
||||
|
||||
getMixNodeBonds(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeBondResponse> {
|
||||
getMixNodesPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedMixnodeResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_mix_node_bonds: {
|
||||
get_mix_nodes: {
|
||||
limit,
|
||||
start_after: startAfter,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getMixNodesDetailed(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeDetailsResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_mix_nodes_detailed: {
|
||||
limit,
|
||||
start_after: startAfter,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getStakeSaturation(mixnetContractAddress: string, mixId: number): Promise<StakeSaturationResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_stake_saturation: { mix_id: mixId },
|
||||
});
|
||||
}
|
||||
|
||||
getMixnodeRewardingDetails(mixnetContractAddress: string, mixId: number): Promise<any> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_mixnode_rewarding_details: { mix_id: mixId },
|
||||
});
|
||||
}
|
||||
|
||||
getGatewaysPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedGatewayResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_gateways: {
|
||||
@@ -81,51 +56,35 @@ export default class NyxdQuerier implements INyxdQuery {
|
||||
});
|
||||
}
|
||||
|
||||
getOwnedMixnode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
ownsMixNode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_owned_mixnode: {
|
||||
owns_mixnode: {
|
||||
address,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getUnbondedMixNodes(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedUnbondedMixnodesResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_unbonded_mix_nodes: { limit, start_after: startAfter },
|
||||
});
|
||||
}
|
||||
|
||||
getUnbondedMixNodeInformation(mixnetContractAddress: string, mixId: number): Promise<UnbondedMixnodeResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_unbonded_mix_node_information: { mix_id: mixId },
|
||||
});
|
||||
}
|
||||
|
||||
ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_owned_gateway: {
|
||||
owns_gateway: {
|
||||
address,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractState> {
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractStateParams> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_state: {},
|
||||
state_params: {},
|
||||
});
|
||||
}
|
||||
|
||||
getAllDelegationsPaged(
|
||||
getAllNetworkDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: [string, string],
|
||||
): Promise<PagedAllDelegationsResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_all_delegations: {
|
||||
get_all_network_delegations: {
|
||||
start_after: startAfter,
|
||||
limit,
|
||||
},
|
||||
@@ -134,13 +93,13 @@ export default class NyxdQuerier implements INyxdQuery {
|
||||
|
||||
getMixNodeDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
mix_id: number,
|
||||
mixIdentity: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixDelegationsResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_mixnode_delegations: {
|
||||
mix_id: mix_id,
|
||||
mix_identity: mixIdentity,
|
||||
start_after: startAfter,
|
||||
limit,
|
||||
},
|
||||
@@ -162,10 +121,10 @@ export default class NyxdQuerier implements INyxdQuery {
|
||||
});
|
||||
}
|
||||
|
||||
getDelegationDetails(mixnetContractAddress: string, mix_id: number, delegator: string): Promise<Delegation> {
|
||||
getDelegationDetails(mixnetContractAddress: string, mixIdentity: string, delegator: string): Promise<Delegation> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_delegation_details: {
|
||||
mix_id: mix_id,
|
||||
mix_identity: mixIdentity,
|
||||
delegator,
|
||||
},
|
||||
});
|
||||
@@ -173,19 +132,44 @@ export default class NyxdQuerier implements INyxdQuery {
|
||||
|
||||
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_layer_distribution: {},
|
||||
layer_distribution: {},
|
||||
});
|
||||
}
|
||||
|
||||
getRewardParams(mixnetContractAddress: string): Promise<RewardingParams> {
|
||||
getRewardPool(mixnetContractAddress: string): Promise<string> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_rewarding_params: {},
|
||||
get_reward_pool: {},
|
||||
});
|
||||
}
|
||||
|
||||
getSpendableCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<any> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
vesting_account_address: vestingAccountAddress,
|
||||
getCirculatingSupply(mixnetContractAddress: string): Promise<string> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_circulating_supply: {},
|
||||
});
|
||||
}
|
||||
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_interval_reward_percent: {},
|
||||
});
|
||||
}
|
||||
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_sybil_resistance_percent: {},
|
||||
});
|
||||
}
|
||||
|
||||
getRewardingStatus(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
rewardingIntervalNonce: number,
|
||||
): Promise<RewardingStatus> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_rewarding_status: {
|
||||
mix_identity: mixIdentity,
|
||||
rewarding_interval_nonce: rewardingIntervalNonce,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +1,75 @@
|
||||
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate';
|
||||
import { CosmWasmClient, JsonObject } from '@cosmjs/cosmwasm-stargate';
|
||||
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';
|
||||
import {
|
||||
Account,
|
||||
Block,
|
||||
Coin,
|
||||
DeliverTxResponse,
|
||||
IndexedTx,
|
||||
SearchTxFilter,
|
||||
SearchTxQuery,
|
||||
SequenceResponse,
|
||||
} from '@cosmjs/stargate';
|
||||
import { Code, CodeDetails, Contract, ContractCodeHistoryEntry } from '@cosmjs/cosmwasm-stargate/build/cosmwasmclient';
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import NyxdQuerier from './nyxd-querier';
|
||||
import {
|
||||
ContractStateParams,
|
||||
Delegation,
|
||||
GatewayBond,
|
||||
GatewayOwnershipResponse,
|
||||
LayerDistribution,
|
||||
MixnetContractVersion,
|
||||
MixNodeDetails,
|
||||
MixNodeBond,
|
||||
MixOwnershipResponse,
|
||||
PagedAllDelegationsResponse,
|
||||
PagedDelegatorDelegationsResponse,
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixNodeBondResponse,
|
||||
PagedMixNodeDetailsResponse,
|
||||
PagedUnbondedMixnodesResponse,
|
||||
StakeSaturationResponse,
|
||||
UnbondedMixnodeResponse,
|
||||
MixNodeBond,
|
||||
MixNodeRewarding,
|
||||
} from '@nymproject/types';
|
||||
import NymApiQuerier, { INymApiQuery } from './nym-api-querier';
|
||||
import { ContractState, ICosmWasmQuery } from './types/shared';
|
||||
import { RewardingParams } from '@nymproject/types';
|
||||
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';
|
||||
PagedMixnodeResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
import NymApiQuerier, { INymApiQuery as INymApiQuery } from './nym-api-querier';
|
||||
|
||||
export interface ICosmWasmQuery {
|
||||
// methods exposed by `CosmWasmClient`
|
||||
getChainId(): Promise<string>;
|
||||
getHeight(): Promise<number>;
|
||||
getAccount(searchAddress: string): Promise<Account | null>;
|
||||
getSequence(address: string): Promise<SequenceResponse>;
|
||||
getBlock(height?: number): Promise<Block>;
|
||||
getBalance(address: string, searchDenom: string): Promise<Coin>;
|
||||
getTx(id: string): Promise<IndexedTx | null>;
|
||||
searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly IndexedTx[]>;
|
||||
disconnect(): void;
|
||||
broadcastTx(tx: Uint8Array, timeoutMs?: number, pollIntervalMs?: number): Promise<DeliverTxResponse>;
|
||||
getCodes(): Promise<readonly Code[]>;
|
||||
getCodeDetails(codeId: number): Promise<CodeDetails>;
|
||||
getContracts(codeId: number): Promise<readonly string[]>;
|
||||
getContract(address: string): Promise<Contract>;
|
||||
getContractCodeHistory(address: string): Promise<readonly ContractCodeHistoryEntry[]>;
|
||||
queryContractRaw(address: string, key: Uint8Array): Promise<Uint8Array | null>;
|
||||
queryContractSmart(address: string, queryMsg: Record<string, unknown>): Promise<JsonObject>;
|
||||
}
|
||||
|
||||
export interface INyxdQuery {
|
||||
// nym-specific implemented inside NymQuerier
|
||||
getContractVersion(mixnetContractAddress: string): Promise<MixnetContractVersion>;
|
||||
getMixNodeBonds(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeBondResponse>;
|
||||
getMixNodesDetailed(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeDetailsResponse>;
|
||||
|
||||
getMixNodesPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedMixnodeResponse>;
|
||||
getGatewaysPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedGatewayResponse>;
|
||||
getOwnedMixnode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse>;
|
||||
ownsMixNode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse>;
|
||||
ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse>;
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractState>;
|
||||
getAllDelegationsPaged(
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractStateParams>;
|
||||
|
||||
getAllNetworkDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: [string, string],
|
||||
): Promise<PagedAllDelegationsResponse>;
|
||||
getMixNodeDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
mix_id: number,
|
||||
mixIdentity: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixDelegationsResponse>;
|
||||
@@ -60,15 +79,21 @@ export interface INyxdQuery {
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedDelegatorDelegationsResponse>;
|
||||
getDelegationDetails(mixnetContractAddress: string, mix_id: number, delegator: string): Promise<Delegation>;
|
||||
getDelegationDetails(mixnetContractAddress: string, mixIdentity: string, delegator: string): Promise<Delegation>;
|
||||
|
||||
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution>;
|
||||
getRewardParams(mixnetContractAddress: string): Promise<RewardingParams>;
|
||||
getStakeSaturation(mixnetContractAddress: string, mixId: number): Promise<StakeSaturationResponse>;
|
||||
getUnbondedMixNodeInformation(mixnetContractAddress: string, mixId: number): Promise<UnbondedMixnodeResponse>;
|
||||
getMixnodeRewardingDetails(mixnetContractAddress: string, mixId: number): Promise<MixNodeRewarding>;
|
||||
getRewardPool(mixnetContractAddress: string): Promise<string>;
|
||||
getCirculatingSupply(mixnetContractAddress: string): Promise<string>;
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number>;
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number>;
|
||||
getRewardingStatus(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
rewardingIntervalNonce: number,
|
||||
): Promise<RewardingStatus>;
|
||||
}
|
||||
|
||||
export interface IQueryClient extends ICosmWasmQuery, INyxdQuery, INymApiQuery {}
|
||||
export interface IQueryClient extends ICosmWasmQuery, INyxdQuery, INymApiQuery { }
|
||||
|
||||
export default class QueryClient extends CosmWasmClient implements IQueryClient {
|
||||
private nyxdQuerier: NyxdQuerier;
|
||||
@@ -90,73 +115,41 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
|
||||
return this.nyxdQuerier.getContractVersion(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getMixNodeBonds(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeBondResponse> {
|
||||
return this.nyxdQuerier.getMixNodeBonds(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getMixNodesDetailed(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeDetailsResponse> {
|
||||
return this.nyxdQuerier.getMixNodesDetailed(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getStakeSaturation(mixnetContractAddress: string, mixId: number): Promise<StakeSaturationResponse> {
|
||||
return this.nyxdQuerier.getStakeSaturation(mixnetContractAddress, mixId);
|
||||
}
|
||||
|
||||
getMixnodeRewardingDetails(mixnetContractAddress: string, mixId: number): Promise<MixNodeRewarding> {
|
||||
return this.nyxdQuerier.getMixnodeRewardingDetails(mixnetContractAddress, mixId);
|
||||
getMixNodesPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedMixnodeResponse> {
|
||||
return this.nyxdQuerier.getMixNodesPaged(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getGatewaysPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedGatewayResponse> {
|
||||
return this.nyxdQuerier.getGatewaysPaged(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getOwnedMixnode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
return this.nyxdQuerier.getOwnedMixnode(mixnetContractAddress, address);
|
||||
ownsMixNode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
return this.nyxdQuerier.ownsMixNode(mixnetContractAddress, address);
|
||||
}
|
||||
|
||||
ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse> {
|
||||
return this.nyxdQuerier.ownsGateway(mixnetContractAddress, address);
|
||||
}
|
||||
|
||||
getUnbondedMixNodes(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedUnbondedMixnodesResponse> {
|
||||
return this.nyxdQuerier.getUnbondedMixNodes(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getUnbondedMixNodeInformation(mixnetContractAddress: string, mixId: number): Promise<UnbondedMixnodeResponse> {
|
||||
return this.nyxdQuerier.getUnbondedMixNodeInformation(mixnetContractAddress, mixId);
|
||||
}
|
||||
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractState> {
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractStateParams> {
|
||||
return this.nyxdQuerier.getStateParams(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getAllDelegationsPaged(
|
||||
getAllNetworkDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: [string, string],
|
||||
): Promise<PagedAllDelegationsResponse> {
|
||||
return this.nyxdQuerier.getAllDelegationsPaged(mixnetContractAddress, limit, startAfter);
|
||||
return this.nyxdQuerier.getAllNetworkDelegationsPaged(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getMixNodeDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
mix_id: number,
|
||||
mixIdentity: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixDelegationsResponse> {
|
||||
return this.nyxdQuerier.getMixNodeDelegationsPaged(mixnetContractAddress, mix_id, limit, startAfter);
|
||||
return this.nyxdQuerier.getMixNodeDelegationsPaged(mixnetContractAddress, mixIdentity, limit, startAfter);
|
||||
}
|
||||
|
||||
getDelegatorDelegationsPaged(
|
||||
@@ -168,16 +161,36 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
|
||||
return this.nyxdQuerier.getDelegatorDelegationsPaged(mixnetContractAddress, delegator, limit, startAfter);
|
||||
}
|
||||
|
||||
getDelegationDetails(mixnetContractAddress: string, mix_id: number, delegator: string): Promise<Delegation> {
|
||||
return this.nyxdQuerier.getDelegationDetails(mixnetContractAddress, mix_id, delegator);
|
||||
getDelegationDetails(mixnetContractAddress: string, mixIdentity: string, delegator: string): Promise<Delegation> {
|
||||
return this.nyxdQuerier.getDelegationDetails(mixnetContractAddress, mixIdentity, delegator);
|
||||
}
|
||||
|
||||
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution> {
|
||||
return this.nyxdQuerier.getLayerDistribution(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getRewardParams(mixnetContractAddress: string): Promise<RewardingParams> {
|
||||
return this.nyxdQuerier.getRewardParams(mixnetContractAddress);
|
||||
getRewardPool(mixnetContractAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getRewardPool(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getCirculatingSupply(mixnetContractAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getCirculatingSupply(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nyxdQuerier.getIntervalRewardPercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nyxdQuerier.getSybilResistancePercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getRewardingStatus(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
rewardingIntervalNonce: number,
|
||||
): Promise<RewardingStatus> {
|
||||
return this.nyxdQuerier.getRewardingStatus(mixnetContractAddress, mixIdentity, rewardingIntervalNonce);
|
||||
}
|
||||
|
||||
getCachedGateways(): Promise<GatewayBond[]> {
|
||||
@@ -188,15 +201,11 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
|
||||
return this.nymApiQuerier.getCachedMixnodes();
|
||||
}
|
||||
|
||||
getActiveMixnodes(): Promise<MixNodeDetails[]> {
|
||||
getActiveMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.nymApiQuerier.getActiveMixnodes();
|
||||
}
|
||||
|
||||
getRewardedMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.nymApiQuerier.getRewardedMixnodes();
|
||||
}
|
||||
|
||||
getSpendableCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<any> {
|
||||
return this.nyxdQuerier.getSpendableCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,22 +25,15 @@ import {
|
||||
MixnetContractVersion,
|
||||
MixNode,
|
||||
MixNodeBond,
|
||||
MixNodeCostParams,
|
||||
MixNodeDetails,
|
||||
MixNodeRewarding,
|
||||
MixOwnershipResponse,
|
||||
PagedAllDelegationsResponse,
|
||||
PagedDelegatorDelegationsResponse,
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixNodeBondResponse,
|
||||
PagedMixNodeDetailsResponse,
|
||||
PagedUnbondedMixnodesResponse,
|
||||
RewardingParams,
|
||||
UnbondedMixnodeResponse,
|
||||
} from '@nymproject/types';
|
||||
PagedMixnodeResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
import NymApiQuerier from './nym-api-querier';
|
||||
import { ContractState } from './types/shared';
|
||||
|
||||
// methods exposed by `SigningCosmWasmClient`
|
||||
export interface ICosmWasmSigning {
|
||||
@@ -150,7 +143,6 @@ export interface ISigningClient extends IQueryClient, ICosmWasmSigning, INymSign
|
||||
bondMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixNode: MixNode,
|
||||
costParams: MixNodeCostParams,
|
||||
ownerSignature: string,
|
||||
pledge: Coin,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
@@ -172,7 +164,7 @@ export interface ISigningClient extends IQueryClient, ICosmWasmSigning, INymSign
|
||||
|
||||
delegateToMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixId: number,
|
||||
mixIdentity: string,
|
||||
amount: Coin,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
memo?: string,
|
||||
@@ -180,14 +172,14 @@ export interface ISigningClient extends IQueryClient, ICosmWasmSigning, INymSign
|
||||
|
||||
undelegateFromMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixId: number,
|
||||
mixIdentity: string,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
memo?: string,
|
||||
): Promise<ExecuteResult>;
|
||||
|
||||
updateMixnodeConfig(
|
||||
mixnetContractAddress: string,
|
||||
mixId: number,
|
||||
mixIdentity: string,
|
||||
profitMarginPercent: number,
|
||||
fee: StdFee | 'auto' | number,
|
||||
): Promise<ExecuteResult>;
|
||||
@@ -243,76 +235,44 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
// query related:
|
||||
|
||||
getContractVersion(mixnetContractAddress: string): Promise<MixnetContractVersion> {
|
||||
return this.getContractVersion(mixnetContractAddress);
|
||||
return this.nyxdQuerier.getContractVersion(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getMixNodeBonds(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeBondResponse> {
|
||||
return this.nyxdQuerier.getMixNodeBonds(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getMixNodesDetailed(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeDetailsResponse> {
|
||||
return this.nyxdQuerier.getMixNodesDetailed(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getStakeSaturation(mixnetContractAddress: string, mixId: number) {
|
||||
return this.nyxdQuerier.getStakeSaturation(mixnetContractAddress, mixId);
|
||||
}
|
||||
|
||||
getUnbondedMixNodeInformation(mixnetContractAddress: string, mixId: number): Promise<UnbondedMixnodeResponse> {
|
||||
return this.nyxdQuerier.getUnbondedMixNodeInformation(mixnetContractAddress, mixId);
|
||||
}
|
||||
|
||||
getMixnodeRewardingDetails(mixnetContractAddress: string, mixId: number): Promise<MixNodeRewarding> {
|
||||
return this.nyxdQuerier.getMixnodeRewardingDetails(mixnetContractAddress, mixId);
|
||||
getMixNodesPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedMixnodeResponse> {
|
||||
return this.nyxdQuerier.getMixNodesPaged(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getGatewaysPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedGatewayResponse> {
|
||||
return this.nyxdQuerier.getGatewaysPaged(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getOwnedMixnode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
return this.nyxdQuerier.getOwnedMixnode(mixnetContractAddress, address);
|
||||
ownsMixNode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
return this.nyxdQuerier.ownsMixNode(mixnetContractAddress, address);
|
||||
}
|
||||
|
||||
ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse> {
|
||||
return this.nyxdQuerier.ownsGateway(mixnetContractAddress, address);
|
||||
}
|
||||
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractState> {
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractStateParams> {
|
||||
return this.nyxdQuerier.getStateParams(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getAllDelegationsPaged(
|
||||
getAllNetworkDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: [string, string],
|
||||
): Promise<PagedAllDelegationsResponse> {
|
||||
return this.getAllDelegationsPaged(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getUnbondedMixNodes(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedUnbondedMixnodesResponse> {
|
||||
return this.nyxdQuerier.getUnbondedMixNodes(mixnetContractAddress, limit, startAfter);
|
||||
return this.nyxdQuerier.getAllNetworkDelegationsPaged(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getMixNodeDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
mix_id: number,
|
||||
mixIdentity: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixDelegationsResponse> {
|
||||
return this.nyxdQuerier.getMixNodeDelegationsPaged(mixnetContractAddress, mix_id, limit, startAfter);
|
||||
return this.nyxdQuerier.getMixNodeDelegationsPaged(mixnetContractAddress, mixIdentity, limit, startAfter);
|
||||
}
|
||||
|
||||
getDelegatorDelegationsPaged(
|
||||
@@ -324,16 +284,36 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
return this.nyxdQuerier.getDelegatorDelegationsPaged(mixnetContractAddress, delegator, limit, startAfter);
|
||||
}
|
||||
|
||||
getDelegationDetails(mixnetContractAddress: string, mix_id: number, delegator: string): Promise<Delegation> {
|
||||
return this.nyxdQuerier.getDelegationDetails(mixnetContractAddress, mix_id, delegator);
|
||||
getDelegationDetails(mixnetContractAddress: string, mixIdentity: string, delegator: string): Promise<Delegation> {
|
||||
return this.nyxdQuerier.getDelegationDetails(mixnetContractAddress, mixIdentity, delegator);
|
||||
}
|
||||
|
||||
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution> {
|
||||
return this.nyxdQuerier.getLayerDistribution(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getRewardParams(mixnetContractAddress: string): Promise<RewardingParams> {
|
||||
return this.nyxdQuerier.getRewardParams(mixnetContractAddress);
|
||||
getRewardPool(mixnetContractAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getRewardPool(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getCirculatingSupply(mixnetContractAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getCirculatingSupply(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nyxdQuerier.getIntervalRewardPercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nyxdQuerier.getSybilResistancePercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getRewardingStatus(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
rewardingIntervalNonce: number,
|
||||
): Promise<RewardingStatus> {
|
||||
return this.nyxdQuerier.getRewardingStatus(mixnetContractAddress, mixIdentity, rewardingIntervalNonce);
|
||||
}
|
||||
|
||||
getCachedGateways(): Promise<GatewayBond[]> {
|
||||
@@ -344,7 +324,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
return this.nymApiQuerier.getCachedMixnodes();
|
||||
}
|
||||
|
||||
getActiveMixnodes(): Promise<MixNodeDetails[]> {
|
||||
getActiveMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.nymApiQuerier.getActiveMixnodes();
|
||||
}
|
||||
|
||||
@@ -352,16 +332,11 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
return this.nymApiQuerier.getRewardedMixnodes();
|
||||
}
|
||||
|
||||
getSpendableCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<any> {
|
||||
return this.nyxdQuerier.getSpendableCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
// signing related:
|
||||
|
||||
bondMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixNode: MixNode,
|
||||
costParams: MixNodeCostParams,
|
||||
ownerSignature: string,
|
||||
pledge: Coin,
|
||||
fee: StdFee | 'auto' | number = 'auto',
|
||||
@@ -373,7 +348,6 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
{
|
||||
bond_mixnode: {
|
||||
mix_node: mixNode,
|
||||
cost_params: costParams,
|
||||
owner_signature: ownerSignature,
|
||||
},
|
||||
},
|
||||
@@ -440,7 +414,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
|
||||
delegateToMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixId: number,
|
||||
mixIdentity: string,
|
||||
amount: Coin,
|
||||
fee: StdFee | 'auto' | number = 'auto',
|
||||
memo = 'Default MixNode Delegation from Typescript',
|
||||
@@ -450,7 +424,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
mixnetContractAddress,
|
||||
{
|
||||
delegate_to_mixnode: {
|
||||
mix_id: mixId,
|
||||
mix_identity: mixIdentity,
|
||||
},
|
||||
},
|
||||
fee,
|
||||
@@ -461,7 +435,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
|
||||
undelegateFromMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixId: number,
|
||||
mixIdentity: string,
|
||||
fee: StdFee | 'auto' | number = 'auto',
|
||||
memo = 'Default MixNode Undelegation from Typescript',
|
||||
): Promise<ExecuteResult> {
|
||||
@@ -470,7 +444,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
mixnetContractAddress,
|
||||
{
|
||||
undelegate_from_mixnode: {
|
||||
mix_id: mixId,
|
||||
mix_identity: mixIdentity,
|
||||
},
|
||||
},
|
||||
fee,
|
||||
@@ -480,14 +454,14 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
|
||||
updateMixnodeConfig(
|
||||
mixnetContractAddress: string,
|
||||
mixId: number,
|
||||
mixIdentity: string,
|
||||
profitMarginPercent: number,
|
||||
fee: StdFee | 'auto' | number,
|
||||
): Promise<ExecuteResult> {
|
||||
return this.execute(
|
||||
this.clientAddress,
|
||||
mixnetContractAddress,
|
||||
{ update_mixnode_config: { profit_margin_percent: profitMarginPercent, mix_id: mixId } },
|
||||
{ update_mixnode_config: { profit_margin_percent: profitMarginPercent, mix_identity: mixIdentity } },
|
||||
fee,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
import expect from 'expect';
|
||||
|
||||
export const amountDemon = {
|
||||
amount: expect.any(String),
|
||||
denom: expect.any(String)
|
||||
}
|
||||
|
||||
export const delegation = {
|
||||
owner: expect.any(String),
|
||||
mix_id: expect.any(Number),
|
||||
cumulative_reward_ratio: expect.any(String),
|
||||
amount: amountDemon,
|
||||
height: expect.any(Number || BigInt),
|
||||
proxy: expect.any(String || null)
|
||||
}
|
||||
|
||||
export const detailedDelegation = {
|
||||
delegation: delegation,
|
||||
mixnode_still_bonded: expect.any(Boolean)
|
||||
}
|
||||
|
||||
export const gateway = {
|
||||
pledge_amount: amountDemon,
|
||||
owner: expect.any(String),
|
||||
block_height: expect.any(Number || BigInt),
|
||||
gateway: {
|
||||
host: expect.any(String),
|
||||
mix_port: expect.any(Number),
|
||||
clients_port: expect.any(Number),
|
||||
location: expect.any(String),
|
||||
sphinx_key: expect.any(String),
|
||||
identity_key: expect.any(String),
|
||||
version: expect.any(String),
|
||||
},
|
||||
proxy: expect.any(String || null)
|
||||
}
|
||||
|
||||
export const pagedGateway = {
|
||||
nodes: gateway,
|
||||
per_page: expect.any(Number),
|
||||
start_next_after: expect.any(Number)
|
||||
}
|
||||
|
||||
export const ownGateway = {
|
||||
address: expect.any(String),
|
||||
gateway: gateway
|
||||
}
|
||||
|
||||
export const rewardingdetails = {
|
||||
cost_params: {
|
||||
profit_margin_percent: expect.any(String),
|
||||
interval_operating_cost: {
|
||||
denom: expect.any(String),
|
||||
amount: expect.any(String)
|
||||
}
|
||||
},
|
||||
operator: expect.any(String),
|
||||
delegates: expect.any(String),
|
||||
total_unit_reward: expect.any(String),
|
||||
unit_delegation: expect.any(String),
|
||||
last_rewarded_epoch: expect.any(Number),
|
||||
unique_delegations: expect.any(Number)
|
||||
}
|
||||
|
||||
export const mix_node = {
|
||||
host: expect.any(String),
|
||||
mix_port: expect.any(Number),
|
||||
verloc_port: expect.any(Number),
|
||||
http_api_port: expect.any(Number),
|
||||
sphinx_key: expect.any(String),
|
||||
identity_key: expect.any(String),
|
||||
version: expect.any(String)
|
||||
}
|
||||
|
||||
export const mixnodebond = {
|
||||
mix_id: expect.any(Number),
|
||||
owner: expect.any(String),
|
||||
original_pledge: {
|
||||
denom: expect.any(String),
|
||||
amount: expect.any(String)
|
||||
},
|
||||
layer: expect.any(String),
|
||||
mix_node: mix_node,
|
||||
proxy: expect.any(String) || null,
|
||||
bonding_height: expect.any(Number || BigInt),
|
||||
is_unbonding: expect.any(Boolean)
|
||||
}
|
||||
|
||||
export const mixnode = {
|
||||
bond_information: mixnodebond,
|
||||
rewarding_details: rewardingdetails
|
||||
}
|
||||
|
||||
export const ownedNode = {
|
||||
address: expect.any(String),
|
||||
mixnode_details: {
|
||||
bond_information: mixnodebond,
|
||||
rewarding_details: rewardingdetails
|
||||
}
|
||||
}
|
||||
|
||||
export const saturation = {
|
||||
mix_id: expect.any(Number),
|
||||
current_saturation: expect.any(String),
|
||||
uncapped_saturation: expect.any(String)
|
||||
}
|
||||
|
||||
export const contractVersion = {
|
||||
build_timestamp: expect.any(String),
|
||||
build_version: expect.any(String),
|
||||
commit_sha: expect.any(String),
|
||||
commit_timestamp: expect.any(String),
|
||||
commit_branch: expect.any(String),
|
||||
rustc_version: expect.any(String)
|
||||
};
|
||||
|
||||
export const stateParams = {
|
||||
minimum_gateway_pledge: amountDemon,
|
||||
minimum_mixnode_pledge: expect.any(String),
|
||||
mixnode_rewarded_set_size: expect.any(Number),
|
||||
mixnode_active_set_size: expect.any(Number)
|
||||
}
|
||||
|
||||
export const contract = {
|
||||
owner: expect.any(Number),
|
||||
rewarding_validator_address: expect.any(Number),
|
||||
vesting_contract_address: expect.any(Number),
|
||||
rewarding_denom: expect.any(String),
|
||||
params: stateParams
|
||||
}
|
||||
|
||||
export const rewardingnode = {
|
||||
mix_id: expect.any(Number),
|
||||
rewarding_details: rewardingdetails
|
||||
}
|
||||
|
||||
export const unbondednode = {
|
||||
mix_id: expect.any(Number),
|
||||
unbonded_info: {
|
||||
identity_key: expect.any(String),
|
||||
owner: expect.any(String),
|
||||
proxy: expect.any(String) || null,
|
||||
unbonding_height: expect.any(Number)
|
||||
}
|
||||
}
|
||||
|
||||
export const allunbondednodes = [
|
||||
expect.any(Number), {
|
||||
identity_key: expect.any(String),
|
||||
owner: expect.any(String),
|
||||
proxy: expect.any(String) || null,
|
||||
unbonding_height: expect.any(Number)
|
||||
}
|
||||
]
|
||||
|
||||
export const layerDistribution = {
|
||||
layer1: expect.any(Number),
|
||||
layer2: expect.any(Number),
|
||||
layer3: expect.any(Number)
|
||||
}
|
||||
|
||||
|
||||
export const intervalRewardParams = {
|
||||
reward_pool: expect.any(Number),
|
||||
staking_supply: expect.any(Number),
|
||||
staking_supply_scale_factor: expect.any(Number),
|
||||
epoch_reward_budget: expect.any(Number),
|
||||
stake_saturation_point: expect.any(Number),
|
||||
sybil_resistance: expect.any(Number),
|
||||
active_set_work_factor: expect.any(Number),
|
||||
interval_pool_emission: expect.any(Number)
|
||||
}
|
||||
|
||||
export const rewardingParams = {
|
||||
interval: intervalRewardParams,
|
||||
rewarded_set_size: expect.any(Number),
|
||||
active_set_size: expect.any(Number)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Mock, Times } from 'moq.ts';
|
||||
import expect from 'expect';
|
||||
import { INyxdQuery } from '../../query-client';
|
||||
|
||||
export class TestHelper {
|
||||
buildMethod = async <T>(methodName: string, args: any[], expectedResult: any): Promise<T> => {
|
||||
const client = new Mock<INyxdQuery>()
|
||||
.setup((nym) => nym[methodName](...args))
|
||||
.returns(Promise.resolve(expectedResult));
|
||||
const obj = client.object();
|
||||
const actualDetails = await obj[methodName](...args);
|
||||
|
||||
client.verify((nym) => nym[methodName](...args), Times.Exactly(1));
|
||||
expect(Object.keys([actualDetails])).toEqual(Object.keys(expectedResult));
|
||||
expect(actualDetails).toBeDefined();
|
||||
|
||||
return actualDetails;
|
||||
};
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import expect from 'expect';
|
||||
import { Delegation } from '@nymproject/types';
|
||||
import { PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse } from '../../types/shared-types';
|
||||
import { TestHelper } from './client';
|
||||
import { mixnet, mixnodeowneraddress, mix_id } from './testData';
|
||||
|
||||
describe('Delegation mock tests', () => {
|
||||
const testHelper = new TestHelper();
|
||||
|
||||
it('get Delegation Details', () => {
|
||||
const execute = testHelper.buildMethod('getDelegationDetails', [mixnet, mix_id, mixnodeowneraddress], <Delegation>{
|
||||
owner: mixnodeowneraddress,
|
||||
mix_id: 0,
|
||||
cumulative_reward_ratio: '',
|
||||
amount: {
|
||||
denom: 'nym',
|
||||
amount: '10',
|
||||
},
|
||||
height: 1314134144132n,
|
||||
proxy: 'null',
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get All Delegations Paged', () => {
|
||||
const execute = testHelper.buildMethod('getAllDelegationsPaged', [mixnet], <PagedAllDelegationsResponse>{
|
||||
delegations: [],
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Delegator Delegations Paged', () => {
|
||||
const execute = testHelper.buildMethod('getDelegatorDelegationsPaged', [mixnet, mixnodeowneraddress], <
|
||||
PagedDelegatorDelegationsResponse
|
||||
>{
|
||||
delegations: [],
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
import expect from 'expect';
|
||||
import { GatewayOwnershipResponse, PagedGatewayResponse } from '../../types/shared-types';
|
||||
import { TestHelper } from './client';
|
||||
import { gatewayowneraddress, mixnet } from './testData';
|
||||
|
||||
describe('Gateway mock tests', () => {
|
||||
const testHelper = new TestHelper();
|
||||
|
||||
it('get Gateways Paged', () => {
|
||||
const execute = testHelper.buildMethod('getGatewaysPaged', [mixnet], <PagedGatewayResponse>{
|
||||
nodes: [],
|
||||
per_page: 25,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('owns Gateway', () => {
|
||||
const execute = testHelper.buildMethod('ownsGateway', [mixnet, gatewayowneraddress], <GatewayOwnershipResponse>{
|
||||
address: gatewayowneraddress,
|
||||
gateway: {},
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,65 +0,0 @@
|
||||
import expect from 'expect';
|
||||
import { LayerDistribution, MixnetContractVersion, StakeSaturationResponse } from '@nymproject/types';
|
||||
import { TestHelper } from './client';
|
||||
import { mixnet, mix_id } from './testData';
|
||||
import { RewardingParams } from '@nymproject/types';
|
||||
import { ContractState } from '../../types/shared';
|
||||
|
||||
describe('Mixnet mock tests', () => {
|
||||
const testHelper = new TestHelper();
|
||||
|
||||
it('get Layer Distribution', () => {
|
||||
const execute = testHelper.buildMethod('getLayerDistribution', [mixnet], <LayerDistribution>{
|
||||
layer1: 2,
|
||||
layer2: 2,
|
||||
layer3: 5,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Reward Params', () => {
|
||||
const execute = testHelper.buildMethod('getRewardParams', [mixnet], <RewardingParams>{
|
||||
interval: {},
|
||||
rewarded_set_size: 0,
|
||||
active_set_size: 0,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Stake Saturation', () => {
|
||||
const execute = testHelper.buildMethod('getStakeSaturation', [mixnet, mix_id], <StakeSaturationResponse>{
|
||||
mix_id: 0,
|
||||
current_saturation: '',
|
||||
uncapped_saturation: '',
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get State Params', () => {
|
||||
const execute = testHelper.buildMethod('getStateParams', [mixnet], <ContractState>{
|
||||
owner: '',
|
||||
rewarding_validator_address: '',
|
||||
vesting_contract_address: '',
|
||||
rewarding_denom: 'unym',
|
||||
params: {
|
||||
minimum_mixnode_pledge: '',
|
||||
minimum_gateway_pledge: '',
|
||||
mixnode_rewarded_set_size: 240,
|
||||
mixnode_active_set_size: 240,
|
||||
},
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Contract Version', () => {
|
||||
const execute = testHelper.buildMethod('getContractVersion', [mixnet], <MixnetContractVersion>{
|
||||
build_timestamp: 'test',
|
||||
commit_branch: 'test',
|
||||
build_version: 'test',
|
||||
rustc_version: 'test',
|
||||
commit_sha: 'test',
|
||||
commit_timestamp: 'test',
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,71 +0,0 @@
|
||||
import expect from 'expect';
|
||||
import {
|
||||
MixNodeRewarding,
|
||||
MixOwnershipResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixNodeBondResponse,
|
||||
PagedMixNodeDetailsResponse,
|
||||
UnbondedMixnodeResponse,
|
||||
} from '@nymproject/types';
|
||||
import { TestHelper } from './client';
|
||||
import { mixnet, mixnodeowneraddress, mix_id } from './testData';
|
||||
|
||||
describe('Mixnode mock tests', () => {
|
||||
const testHelper = new TestHelper();
|
||||
|
||||
it('get Mixnode Bonds', () => {
|
||||
const execute = testHelper.buildMethod('getMixNodeBonds', [mixnet], <PagedMixNodeBondResponse>{
|
||||
nodes: [],
|
||||
per_page: 25,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Mixnode Delegations Paged', () => {
|
||||
const execute = testHelper.buildMethod('getMixNodeDelegationsPaged', [mixnet, mix_id], <
|
||||
PagedMixDelegationsResponse
|
||||
>{
|
||||
delegations: [],
|
||||
per_page: 25,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Mixnodes Detailed', () => {
|
||||
const execute = testHelper.buildMethod('getMixNodesDetailed', [mixnet], <PagedMixNodeDetailsResponse>{
|
||||
nodes: [],
|
||||
per_page: 25,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Mixnode Rewarding Details', () => {
|
||||
const execute = testHelper.buildMethod('getMixnodeRewardingDetails', [mixnet, mix_id], <MixNodeRewarding>{
|
||||
cost_params: {},
|
||||
operator: '',
|
||||
delegates: '',
|
||||
total_unit_reward: '',
|
||||
unit_delegation: '',
|
||||
last_rewarded_epoch: 1,
|
||||
unique_delegations: 1,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Owned Mixnode', () => {
|
||||
const execute = testHelper.buildMethod('getOwnedMixnode', [mixnet, mixnodeowneraddress], <MixOwnershipResponse>{
|
||||
address: '',
|
||||
mixnode: {},
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Unbonded Mixnode Information', () => {
|
||||
const execute = testHelper.buildMethod(
|
||||
'getUnbondedMixNodeInformation',
|
||||
[mixnet, mix_id],
|
||||
<UnbondedMixnodeResponse>{},
|
||||
);
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,8 +0,0 @@
|
||||
export const mixnet = 'n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g';
|
||||
export const gatewayowneraddress = 'n16evnn8glr0sham3matj8rg2s24m6x56ayk87ts';
|
||||
// export const mixId = 436207616;
|
||||
export const mix_id = 26;
|
||||
export const nodeIdentityKey = 'ATmVJknZarDF6Yj53M7h8NS9LLCUvWuToXpk3pDvYUH1';
|
||||
export const mixnodeowneraddress = 'n1fzv4jc7fanl9s0qj02ge2ezk3kts545kjtek47';
|
||||
export const delegatorAddress = 'n1lemst75va9700tsrxq58adzujrh6h9s5x60h9h';
|
||||
export const rewardingIntervalNonce = 1;
|
||||
@@ -1,180 +0,0 @@
|
||||
import expect from 'expect';
|
||||
import ValidatorClient from '../../index';
|
||||
|
||||
import {
|
||||
allunbondednodes,
|
||||
contract,
|
||||
delegation,
|
||||
gateway,
|
||||
layerDistribution,
|
||||
mixnode,
|
||||
mixnodebond,
|
||||
ownedNode,
|
||||
ownGateway,
|
||||
rewardingnode,
|
||||
saturation,
|
||||
unbondednode,
|
||||
} from '../expectedResponses';
|
||||
import { delegatorAddress, gatewayowneraddress } from '../mock/testData';
|
||||
|
||||
const dotenv = require('dotenv');
|
||||
|
||||
dotenv.config();
|
||||
|
||||
describe('Mixnet queries', () => {
|
||||
let client: ValidatorClient;
|
||||
|
||||
beforeEach(async () => {
|
||||
client = await ValidatorClient.connectForQuery(
|
||||
process.env.rpcAddress || '',
|
||||
process.env.validatorAddress || '',
|
||||
process.env.prefix || '',
|
||||
process.env.mixnetContractAddress || '',
|
||||
process.env.vestingContractAddress || '',
|
||||
process.env.denom || '',
|
||||
);
|
||||
});
|
||||
|
||||
//
|
||||
// CONTRACT
|
||||
//
|
||||
|
||||
it('can query for an account balance', async () => {
|
||||
const balance = await client.getBalance('n1ptg680vnmef2cd8l0s9uyc4f0hgf3x8sed6w77');
|
||||
expect(Number.parseFloat(balance.amount)).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('can query for stake saturation', async () => {
|
||||
const stakeSaturation = await client.getStakeSaturation(7);
|
||||
expect(Object.keys(stakeSaturation)).toEqual(Object.keys(saturation));
|
||||
expect(stakeSaturation).toBeTruthy();
|
||||
expect(stakeSaturation?.current_saturation).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for contract version', async () => {
|
||||
const contractV = await client.getMixnetContractVersion();
|
||||
expect(contractV).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for mixnet contract settings', async () => {
|
||||
const settings = await client.getMixnetContractSettings();
|
||||
expect(Object.keys(settings)).toEqual(Object.keys(contract));
|
||||
expect(settings).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for reward pool', async () => {
|
||||
const rewardPool = await client.getRewardParams();
|
||||
// TODO add velidation here
|
||||
expect(rewardPool).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for layer distribution', async () => {
|
||||
const layer = await client.getLayerDistribution();
|
||||
expect(Object.keys(layer)).toEqual(Object.keys(layerDistribution));
|
||||
expect(layer).toBeTruthy();
|
||||
});
|
||||
|
||||
//
|
||||
// MIXNODES
|
||||
//
|
||||
|
||||
it('can query for unbonded mixnodes', async () => {
|
||||
const unbondedNodes = await client.getUnbondedMixNodes();
|
||||
for (let i = 0; i < unbondedNodes.length; i++) {
|
||||
expect(Object.keys(unbondedNodes[0])).toEqual(Object.keys(allunbondednodes));
|
||||
expect(unbondedNodes).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
it('can query for unbonded mixnode information', async () => {
|
||||
const unbondedMixnodeInfo = await client.getUnbondedMixNodeInformation(1);
|
||||
expect(Object.keys(unbondedMixnodeInfo)).toEqual(Object.keys(unbondednode));
|
||||
expect(unbondedMixnodeInfo).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for mixnode rewarding details', async () => {
|
||||
const rewardingDetails = await client.getMixnodeRewardingDetails(1);
|
||||
expect(Object.keys(rewardingDetails)).toEqual(Object.keys(rewardingnode));
|
||||
expect(rewardingDetails).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for owned mixnode', async () => {
|
||||
const ownedMixnode = await client.getOwnedMixnode('n1ptg680vnmef2cd8l0s9uyc4f0hgf3x8sed6w77');
|
||||
expect(Object.keys(ownedMixnode)).toEqual(Object.keys(ownedNode));
|
||||
expect(ownedMixnode).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for all mixnode bonds', async () => {
|
||||
const mixnodeBonds = await client.getMixNodeBonds();
|
||||
expect(Object.keys(mixnodeBonds[0])).toEqual(Object.keys(mixnodebond));
|
||||
expect(mixnodeBonds).toBeTruthy();
|
||||
expect(Array.isArray(mixnodeBonds)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for all mixnode details', async () => {
|
||||
const mixnodeDetails = await client.getMixNodesDetailed();
|
||||
expect(Object.keys(mixnodeDetails[0])).toEqual(Object.keys(mixnode));
|
||||
expect(mixnodeDetails).toBeTruthy();
|
||||
expect(Array.isArray(mixnodeDetails)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for all active mixnodes', async () => {
|
||||
const activeNodes = await client.getActiveMixnodes();
|
||||
expect(Object.keys(activeNodes[0])).toEqual(Object.keys(mixnode));
|
||||
expect(activeNodes).toBeTruthy();
|
||||
expect(Array.isArray(activeNodes)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for rewarded mixnodes', async () => {
|
||||
const rewardNodes = await client.getRewardedMixnodes();
|
||||
expect(Object.keys(rewardNodes[0])).toEqual(Object.keys(mixnode));
|
||||
expect(rewardNodes).toBeTruthy();
|
||||
});
|
||||
|
||||
//
|
||||
// DELEGATIONS
|
||||
//
|
||||
|
||||
it('can query for account delegations', async () => {
|
||||
const delegations = await client.getAllNyxdDelegatorDelegations('n1fzv4jc7fanl9s0qj02ge2ezk3kts545kjtek47');
|
||||
expect(Object.keys(delegations[0])).toEqual(Object.keys(delegation));
|
||||
expect(delegations).toBeTruthy();
|
||||
expect(Array.isArray(delegations)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for all delegations', async () => {
|
||||
const allDelegations = await client.getAllNyxdDelegations();
|
||||
expect(Object.keys(allDelegations[0])).toEqual(Object.keys(delegation));
|
||||
expect(allDelegations).toBeTruthy();
|
||||
expect(Array.isArray(allDelegations)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for all delegations on a node', async () => {
|
||||
const mixnodeDelegations = await client.getAllNyxdSingleMixnodeDelegations(1);
|
||||
expect(Object.keys(mixnodeDelegations[0])).toEqual(Object.keys(delegation));
|
||||
expect(mixnodeDelegations).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can query for detailed delegations', async () => {
|
||||
const detailedDelegation = await client.getDelegationDetails(7, delegatorAddress);
|
||||
expect(Object.keys(detailedDelegation)).toEqual(Object.keys(detailedDelegation));
|
||||
expect(detailedDelegation).toBeTruthy();
|
||||
});
|
||||
|
||||
//
|
||||
// GATEWAYS
|
||||
//
|
||||
|
||||
it('can query for all gateways', async () => {
|
||||
const gateways = await client.getAllNyxdGateways();
|
||||
expect(Object.keys(gateways[0])).toEqual(Object.keys(gateway));
|
||||
expect(gateways).toBeTruthy();
|
||||
expect(Array.isArray(gateways)).toBeTruthy();
|
||||
}).timeout(10000);
|
||||
|
||||
it('can query for owned gateway', async () => {
|
||||
const gateway = await client.ownsGateway(gatewayowneraddress);
|
||||
expect(Object.keys(gateway)).toEqual(Object.keys(ownGateway));
|
||||
expect(gateway).toBeTruthy();
|
||||
}).timeout(10000);
|
||||
});
|
||||
@@ -1,28 +0,0 @@
|
||||
import expect from 'expect';
|
||||
import ValidatorClient from '../../index';
|
||||
|
||||
const dotenv = require('dotenv');
|
||||
|
||||
dotenv.config();
|
||||
|
||||
describe('Vesting queries', () => {
|
||||
let client: ValidatorClient;
|
||||
|
||||
beforeEach(async () => {
|
||||
client = await ValidatorClient.connectForQuery(
|
||||
process.env.rpcAddress || '',
|
||||
process.env.validatorAddress || '',
|
||||
process.env.prefix || '',
|
||||
process.env.mixnetContractAddress || '',
|
||||
process.env.vestingContractAddress || '',
|
||||
process.env.denom || '',
|
||||
);
|
||||
});
|
||||
|
||||
it('can query for contract version', async () => {
|
||||
const contract = await client.getVestingContractVersion();
|
||||
expect(contract).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get the balance on the account', () => {});
|
||||
});
|
||||
@@ -1,107 +0,0 @@
|
||||
import expect from 'expect';
|
||||
import ValidatorClient from '../../';
|
||||
|
||||
const dotenv = require('dotenv');
|
||||
|
||||
dotenv.config();
|
||||
|
||||
// TODO: implement for QA with .env for mnemonics
|
||||
describe('Mixnet actions', () => {
|
||||
let client: ValidatorClient;
|
||||
|
||||
beforeEach(async () => {
|
||||
client = await ValidatorClient.connect(
|
||||
process.env.mnemonic || '',
|
||||
process.env.rpcAddress || '',
|
||||
process.env.validatorAddress || '',
|
||||
process.env.prefix || '',
|
||||
process.env.mixnetContractAddress || '',
|
||||
process.env.vestingContractAddress || '',
|
||||
process.env.denom || '',
|
||||
);
|
||||
});
|
||||
|
||||
it('can send tokens', async () => {
|
||||
const res = await client.send(client.address, [{ amount: '10000000', denom: 'unym' }]);
|
||||
expect(res.transactionHash).toBeDefined();
|
||||
}).timeout(10000);
|
||||
|
||||
it.skip('can delegate tokens', async () => {
|
||||
const [_, secondMixnode] = await client.getActiveMixnodes();
|
||||
|
||||
if (secondMixnode) {
|
||||
const res = await client.delegateToMixNode(
|
||||
secondMixnode.bond_information.mix_id,
|
||||
{
|
||||
amount: '15000000',
|
||||
denom: 'unym',
|
||||
},
|
||||
{ gas: '1000000', amount: [{ amount: '100000', denom: 'unym' }] },
|
||||
);
|
||||
expect(res.transactionHash).toBeDefined();
|
||||
}
|
||||
}).timeout(10000);
|
||||
|
||||
// Need to provide a mix id that can be undelegated from
|
||||
it.skip('can undelegate from a mixnode', async () => {
|
||||
const mixId = 8;
|
||||
const res = await client.undelegateFromMixNode(mixId);
|
||||
expect(res.transactionHash).toBeDefined();
|
||||
});
|
||||
|
||||
it.skip('Can unbond a mixnode', async () => {
|
||||
const res = await client.unbondMixNode();
|
||||
expect(res.transactionHash).toBeDefined();
|
||||
}).timeout(10000);
|
||||
|
||||
it.skip('Can bond a mixnode', async () => {
|
||||
const res = await client.bondMixNode(
|
||||
{
|
||||
identity_key: '3P6pAcF2p3pYMqWdpHqhbavu3ifyaBs5Qw5UmmCGwimx',
|
||||
sphinx_key: 'GQMQKwUThaggatA6oZteSWTsCQoUfmLtamJ7o9YkP9aE',
|
||||
host: '109.74.195.67',
|
||||
mix_port: 1789,
|
||||
verloc_port: 1790,
|
||||
http_api_port: 8000,
|
||||
version: '1.1.4',
|
||||
},
|
||||
'3rXWCQBUj5JQB3UBUkZcXhCk9Zh3cjduMF8aFHPTG7KTkkhZzDJTNmE2p2Ph1g6iQW5vRGTpQzjXF33WDwvhzHk6',
|
||||
{ profit_margin_percent: '0.1', interval_operating_cost: { amount: '40', denom: 'nym' } },
|
||||
{ amount: '100_000_000', denom: 'unym' },
|
||||
{ gas: '1000000', amount: [{ amount: '100000', denom: 'unym' }] },
|
||||
);
|
||||
expect(res.transactionHash).toBeDefined();
|
||||
}).timeout(10000);
|
||||
|
||||
it.skip('can unbond a gateway', async () => {
|
||||
const res = await client.unbondGateway();
|
||||
expect(res.transactionHash).toBeDefined();
|
||||
});
|
||||
|
||||
it.skip('can bond a gateway', async () => {
|
||||
const res = await client.bondGateway(
|
||||
{
|
||||
identity_key: '36vfvEyBzo5cWEFbnP7fqgY39kFw9PQhvwzbispeNaxL',
|
||||
sphinx_key: 'G65Fwc2JNAotuHQFqmDKhQNQL5rn3r9pupUdmxMygNUZ',
|
||||
host: '151.236.220.82',
|
||||
version: '1.1.4',
|
||||
mix_port: 1789,
|
||||
clients_port: 9000,
|
||||
location: 'Cuba',
|
||||
},
|
||||
'3ipSJksWHehZm1YfuH5Ahtg7b22NnrP9hEs6iEDXfUS5uiUhpWmCjGR3b3NDHuxeGjpZYJNYJ52D8WCPK5ZR7Szj',
|
||||
{ amount: '100_000_000', denom: 'unym' },
|
||||
);
|
||||
expect(res.transactionHash).toBeDefined();
|
||||
});
|
||||
|
||||
it.skip('can update contract state params', async () => {
|
||||
const res = await client.updateContractStateParams({
|
||||
minimum_mixnode_pledge: '',
|
||||
minimum_gateway_pledge: '',
|
||||
mixnode_rewarded_set_size: 2,
|
||||
mixnode_active_set_size: 2,
|
||||
});
|
||||
expect(res.transactionHash).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"exclude": [
|
||||
"tests",
|
||||
"dist",
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
import { Coin } from '@cosmjs/stargate';
|
||||
|
||||
// TODO: ideally we'd have re-exported those using that fancy crate that builds ts types from rust
|
||||
|
||||
export type MixnetContractVersion = {
|
||||
build_timestamp: string;
|
||||
build_version: string;
|
||||
commit_sha: string;
|
||||
commit_timestamp: string;
|
||||
commit_branch: string;
|
||||
rustc_version: string;
|
||||
};
|
||||
|
||||
export type PagedMixnodeResponse = {
|
||||
nodes: MixNodeBond[];
|
||||
per_page: number;
|
||||
start_next_after?: string;
|
||||
};
|
||||
|
||||
export type PagedGatewayResponse = {
|
||||
nodes: GatewayBond[];
|
||||
per_page: number;
|
||||
start_next_after?: string;
|
||||
};
|
||||
|
||||
export type MixOwnershipResponse = {
|
||||
address: string;
|
||||
mixnode?: MixNodeBond;
|
||||
};
|
||||
|
||||
export type GatewayOwnershipResponse = {
|
||||
address: string;
|
||||
gateway?: GatewayBond;
|
||||
};
|
||||
|
||||
export type ContractStateParams = {
|
||||
// ideally I'd want to define those as `number` rather than `string`, but
|
||||
// rust-side they are defined as Uint128 and that don't have
|
||||
// native javascript representations and therefore are interpreted as strings after deserialization
|
||||
minimum_mixnode_pledge: string;
|
||||
minimum_gateway_pledge: string;
|
||||
mixnode_rewarded_set_size: number;
|
||||
mixnode_active_set_size: number;
|
||||
};
|
||||
|
||||
export type LayerDistribution = {
|
||||
gateways: number;
|
||||
layer1: number;
|
||||
layer2: number;
|
||||
layer3: number;
|
||||
};
|
||||
|
||||
export type Delegation = {
|
||||
owner: string;
|
||||
node_identity: string;
|
||||
amount: Coin;
|
||||
block_height: number;
|
||||
proxy?: string;
|
||||
};
|
||||
|
||||
export type PagedMixDelegationsResponse = {
|
||||
delegations: Delegation[];
|
||||
start_next_after?: string;
|
||||
};
|
||||
|
||||
export type PagedDelegatorDelegationsResponse = {
|
||||
delegations: Delegation[];
|
||||
start_next_after?: string;
|
||||
};
|
||||
|
||||
export type PagedAllDelegationsResponse = {
|
||||
delegations: Delegation[];
|
||||
start_next_after?: [string, string];
|
||||
};
|
||||
|
||||
export type RewardingResult = {
|
||||
operator_reward: string;
|
||||
total_delegator_reward: string;
|
||||
};
|
||||
|
||||
export type NodeRewardParams = {
|
||||
period_reward_pool: string;
|
||||
k: string;
|
||||
reward_blockstamp: number;
|
||||
circulating_supply: string;
|
||||
uptime: string;
|
||||
sybil_resistance_percent: number;
|
||||
};
|
||||
|
||||
export type DelegatorRewardParams = {
|
||||
node_reward_params: NodeRewardParams;
|
||||
sigma: number;
|
||||
profit_margin: number;
|
||||
node_profit: number;
|
||||
};
|
||||
|
||||
export type PendingDelegatorRewarding = {
|
||||
running_results: RewardingResult;
|
||||
next_start: string;
|
||||
rewarding_params: DelegatorRewardParams;
|
||||
};
|
||||
|
||||
export type RewardingStatus = { Complete: RewardingResult } | { PendingNextDelegatorPage: PendingDelegatorRewarding };
|
||||
|
||||
export type MixnodeRewardingStatusResponse = {
|
||||
status?: RewardingStatus;
|
||||
};
|
||||
|
||||
export enum Layer {
|
||||
Gateway,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
}
|
||||
|
||||
export type MixNodeBond = {
|
||||
owner: string;
|
||||
mix_node: MixNode;
|
||||
layer: Layer;
|
||||
bond_amount: Coin;
|
||||
total_delegation: Coin;
|
||||
};
|
||||
|
||||
export type MixNode = {
|
||||
host: string;
|
||||
mix_port: number;
|
||||
verloc_port: number;
|
||||
http_api_port: number;
|
||||
sphinx_key: string;
|
||||
identity_key: string;
|
||||
version: string;
|
||||
profit_margin_percent: number;
|
||||
};
|
||||
|
||||
export type GatewayBond = {
|
||||
owner: string;
|
||||
gateway: Gateway;
|
||||
|
||||
bond_amount: Coin;
|
||||
total_delegation: Coin;
|
||||
};
|
||||
|
||||
export type Gateway = {
|
||||
host: string;
|
||||
mix_port: number;
|
||||
clients_port: number;
|
||||
location: string;
|
||||
sphinx_key: string;
|
||||
identity_key: string;
|
||||
version: string;
|
||||
};
|
||||
|
||||
export type SendRequest = {
|
||||
senderAddress: string;
|
||||
recipientAddress: string;
|
||||
transferAmount: readonly Coin[];
|
||||
};
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
declare namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
rpcAddress: string;
|
||||
validatorAddress: string;
|
||||
prefix: string;
|
||||
mixnetContractAddress: string;
|
||||
vestingContractAddress: string;
|
||||
denom: string;
|
||||
mnemonic: string;
|
||||
}
|
||||
}
|
||||
@@ -1,259 +0,0 @@
|
||||
import { JsonObject } from '@cosmjs/cosmwasm-stargate';
|
||||
import { Code, CodeDetails, Contract, ContractCodeHistoryEntry } from '@cosmjs/cosmwasm-stargate/build/cosmwasmclient';
|
||||
import {
|
||||
Account,
|
||||
Block,
|
||||
Coin,
|
||||
DeliverTxResponse,
|
||||
IndexedTx,
|
||||
SearchTxFilter,
|
||||
SearchTxQuery,
|
||||
SequenceResponse,
|
||||
} from '@cosmjs/stargate';
|
||||
import {
|
||||
MixNodeRewarding,
|
||||
PagedMixNodeBondResponse,
|
||||
PagedMixNodeDetailsResponse,
|
||||
StakeSaturationResponse,
|
||||
UnbondedMixnodeResponse,
|
||||
} from '@nymproject/types';
|
||||
|
||||
export type MixnetContractVersion = {
|
||||
build_timestamp: string;
|
||||
build_version: string;
|
||||
commit_sha: string;
|
||||
commit_timestamp: string;
|
||||
commit_branch: string;
|
||||
rustc_version: string;
|
||||
};
|
||||
|
||||
export type PagedMixnodeResponse = {
|
||||
nodes: MixNodeBond[];
|
||||
per_page: number;
|
||||
start_next_after?: string;
|
||||
};
|
||||
|
||||
export type PagedGatewayResponse = {
|
||||
nodes: GatewayBond[];
|
||||
per_page: number;
|
||||
start_next_after?: string;
|
||||
};
|
||||
|
||||
export type MixOwnershipResponse = {
|
||||
address: string;
|
||||
mixnode?: MixNodeBond;
|
||||
};
|
||||
|
||||
export type GatewayOwnershipResponse = {
|
||||
address: string;
|
||||
gateway?: GatewayBond;
|
||||
};
|
||||
|
||||
export type ContractStateParams = {
|
||||
// ideally I'd want to define those as `number` rather than `string`, but
|
||||
// rust-side they are defined as Uint128 and that don't have
|
||||
// native javascript representations and therefore are interpreted as strings after deserialization
|
||||
minimum_mixnode_pledge: string;
|
||||
minimum_gateway_pledge: string;
|
||||
mixnode_rewarded_set_size: number;
|
||||
mixnode_active_set_size: number;
|
||||
};
|
||||
|
||||
export type LayerDistribution = {
|
||||
gateways: number;
|
||||
layer1: number;
|
||||
layer2: number;
|
||||
layer3: number;
|
||||
};
|
||||
|
||||
export type Delegation = {
|
||||
owner: string;
|
||||
node_identity: string;
|
||||
amount: Coin;
|
||||
block_height: number;
|
||||
proxy?: string;
|
||||
};
|
||||
|
||||
export type PagedMixDelegationsResponse = {
|
||||
delegations: Delegation[];
|
||||
start_next_after?: string;
|
||||
};
|
||||
|
||||
export type PagedDelegatorDelegationsResponse = {
|
||||
delegations: Delegation[];
|
||||
start_next_after?: string;
|
||||
};
|
||||
|
||||
export type PagedAllDelegationsResponse = {
|
||||
delegations: Delegation[];
|
||||
start_next_after?: [string, string];
|
||||
};
|
||||
|
||||
export type RewardingResult = {
|
||||
operator_reward: string;
|
||||
total_delegator_reward: string;
|
||||
};
|
||||
|
||||
export type NodeRewardParams = {
|
||||
period_reward_pool: string;
|
||||
k: string;
|
||||
reward_blockstamp: number;
|
||||
circulating_supply: string;
|
||||
uptime: string;
|
||||
sybil_resistance_percent: number;
|
||||
};
|
||||
|
||||
export type DelegatorRewardParams = {
|
||||
node_reward_params: NodeRewardParams;
|
||||
sigma: number;
|
||||
profit_margin: number;
|
||||
node_profit: number;
|
||||
};
|
||||
|
||||
export type PendingDelegatorRewarding = {
|
||||
running_results: RewardingResult;
|
||||
next_start: string;
|
||||
rewarding_params: DelegatorRewardParams;
|
||||
};
|
||||
|
||||
export type RewardingStatus = { Complete: RewardingResult } | { PendingNextDelegatorPage: PendingDelegatorRewarding };
|
||||
|
||||
export type MixnodeRewardingStatusResponse = {
|
||||
status?: RewardingStatus;
|
||||
};
|
||||
|
||||
export enum Layer {
|
||||
Gateway,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
}
|
||||
|
||||
export type MixNodeBond = {
|
||||
owner: string;
|
||||
mix_node: MixNode;
|
||||
layer: Layer;
|
||||
bond_amount: Coin;
|
||||
total_delegation: Coin;
|
||||
};
|
||||
|
||||
export type MixNode = {
|
||||
host: string;
|
||||
mix_port: number;
|
||||
verloc_port: number;
|
||||
http_api_port: number;
|
||||
sphinx_key: string;
|
||||
identity_key: string;
|
||||
version: string;
|
||||
profit_margin_percent: number;
|
||||
};
|
||||
|
||||
export type GatewayBond = {
|
||||
owner: string;
|
||||
gateway: Gateway;
|
||||
|
||||
bond_amount: Coin;
|
||||
total_delegation: Coin;
|
||||
};
|
||||
|
||||
export type Gateway = {
|
||||
host: string;
|
||||
mix_port: number;
|
||||
clients_port: number;
|
||||
location: string;
|
||||
sphinx_key: string;
|
||||
identity_key: string;
|
||||
version: string;
|
||||
};
|
||||
|
||||
export type SendRequest = {
|
||||
senderAddress: string;
|
||||
recipientAddress: string;
|
||||
transferAmount: readonly Coin[];
|
||||
};
|
||||
|
||||
export interface SmartContractQuery {
|
||||
queryContractSmart(address: string, queryMsg: Record<string, unknown>): Promise<JsonObject>;
|
||||
}
|
||||
export interface ICosmWasmQuery {
|
||||
// methods exposed by `CosmWasmClient`
|
||||
getChainId(): Promise<string>;
|
||||
getHeight(): Promise<number>;
|
||||
getAccount(searchAddress: string): Promise<Account | null>;
|
||||
getSequence(address: string): Promise<SequenceResponse>;
|
||||
getBlock(height?: number): Promise<Block>;
|
||||
getBalance(address: string, searchDenom: string): Promise<Coin>;
|
||||
getTx(id: string): Promise<IndexedTx | null>;
|
||||
searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly IndexedTx[]>;
|
||||
disconnect(): void;
|
||||
broadcastTx(tx: Uint8Array, timeoutMs?: number, pollIntervalMs?: number): Promise<DeliverTxResponse>;
|
||||
getCodes(): Promise<readonly Code[]>;
|
||||
getCodeDetails(codeId: number): Promise<CodeDetails>;
|
||||
getContracts(codeId: number): Promise<readonly string[]>;
|
||||
getContract(address: string): Promise<Contract>;
|
||||
getContractCodeHistory(address: string): Promise<readonly ContractCodeHistoryEntry[]>;
|
||||
queryContractRaw(address: string, key: Uint8Array): Promise<Uint8Array | null>;
|
||||
queryContractSmart(address: string, queryMsg: Record<string, unknown>): Promise<JsonObject>;
|
||||
}
|
||||
|
||||
export interface INymdQuery {
|
||||
// nym-specific implemented inside NymQuerier
|
||||
getContractVersion(mixnetContractAddress: string): Promise<MixnetContractVersion>;
|
||||
getMixNodeBonds(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeBondResponse>;
|
||||
getMixNodesDetailed(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeDetailsResponse>;
|
||||
getGatewaysPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedGatewayResponse>;
|
||||
getOwnedMixnode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse>;
|
||||
ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse>;
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractState>;
|
||||
getAllNetworkDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: [string, string],
|
||||
): Promise<PagedAllDelegationsResponse>;
|
||||
getMixNodeDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
mix_id: number,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixDelegationsResponse>;
|
||||
getDelegatorDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
delegator: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedDelegatorDelegationsResponse>;
|
||||
getDelegationDetails(mixnetContractAddress: string, mix_id: number, delegator: string): Promise<Delegation>;
|
||||
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution>;
|
||||
getStakeSaturation(mixnetContractAddress: string, mixId: number): Promise<StakeSaturationResponse>;
|
||||
getUnbondedMixNodeInformation(mixnetContractAddress: string, mixId: number): Promise<UnbondedMixnodeResponse>;
|
||||
getMixnodeRewardingDetails(mixnetContractAddress: string, mixId: number): Promise<MixNodeRewarding>;
|
||||
}
|
||||
|
||||
export interface IVestingQuerier {
|
||||
getVestingContractVersion(mixnetContractAddress: string): Promise<MixnetContractVersion>;
|
||||
}
|
||||
|
||||
export interface MappedCoin {
|
||||
readonly denom: string;
|
||||
readonly fractionalDigits: number;
|
||||
}
|
||||
|
||||
export interface CoinMap {
|
||||
readonly [key: string]: MappedCoin;
|
||||
}
|
||||
|
||||
export interface ContractState {
|
||||
owner: string;
|
||||
rewarding_validator_address: string;
|
||||
vesting_contract_address: string;
|
||||
rewarding_denom: string;
|
||||
params: ContractStateParams;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import ValidatorClient from '../../validator/index';
|
||||
import expect from 'expect';
|
||||
|
||||
describe('Query: balances', () => {
|
||||
it('can query for an account balance', async () => {
|
||||
const client = await ValidatorClient.connectForQuery(
|
||||
'https://rpc.nymtech.net/', 'https://validator.nymtech.net/api/', 'n', 'n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g', 'n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw', 'nym');
|
||||
const balance = await client.getBalance('n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy');
|
||||
expect(Number.parseFloat(balance.amount)).toBeGreaterThan(0);
|
||||
}).timeout(5000);
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
import ValidatorClient from '../../dist';
|
||||
import expect from 'expect';
|
||||
|
||||
// TODO: implement for QA with .env for mnemonics
|
||||
// describe('Sign: send', () => {
|
||||
// it('can send tokens', async () => {
|
||||
// const client = await ValidatorClient.connect(
|
||||
// '<ADD MNEMONIC HERE>',
|
||||
// 'https://rpc.nyx.nodes.guru/', 'https://validator.nymtech.net/api/', 'n', 'n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g', 'n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw', 'nym');
|
||||
// await client.send('<ADD ADDRESS HERE>')
|
||||
// const balance = await client.getBalance('n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy');
|
||||
// expect(Number.parseFloat(balance.amount)).toBeGreaterThan(0);
|
||||
// }).timeout(5000);
|
||||
// })
|
||||
@@ -1,22 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/nym-validator-client",
|
||||
"module": "ES2020",
|
||||
"target": "es2021",
|
||||
"allowJs": false,
|
||||
"strict": true,
|
||||
"lib": ["es2021", "dom", "dom.iterable", "esnext"],
|
||||
"moduleResolution": "node",
|
||||
"skipDefaultLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"skipLibCheck": true,
|
||||
"noImplicitAny": true,
|
||||
"typeRoots": ["./src/types/global.d.ts"]
|
||||
},
|
||||
"typedocOptions": {
|
||||
"entryPoints": ["./src/index.ts"],
|
||||
"out": "docs"
|
||||
},
|
||||
"exclude": ["dist", "./src/tests/**/*", "node_module"]
|
||||
}
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"typedocOptions": {
|
||||
"entryPoints": [
|
||||
"src/index.ts"
|
||||
],
|
||||
"out": "docs"
|
||||
},
|
||||
"exclude": [
|
||||
"dist",
|
||||
"examples",
|
||||
"tests",
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "CommonJS"
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,8 @@ wasm-bindgen-futures = "0.4"
|
||||
|
||||
# internal
|
||||
client-core = { path = "../client-core", default-features = false, features = ["wasm"] }
|
||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
coconut-interface = { path = "../../common/coconut-interface" }
|
||||
credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm"] }
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "bandwidth-claim-contract"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
schemars = "0.8"
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// Serializable structures for what we find in common/crypto
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct PublicKey([u8; 32]);
|
||||
|
||||
impl PublicKey {
|
||||
pub fn new(bytes: [u8; 32]) -> Self {
|
||||
PublicKey(bytes)
|
||||
}
|
||||
pub fn to_bytes(&self) -> [u8; 32] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for PublicKey {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct Signature([u8; 32], [u8; 32]);
|
||||
|
||||
impl Signature {
|
||||
pub fn new(bytes: [u8; 64]) -> Self {
|
||||
let mut sig1 = [0u8; 32];
|
||||
let mut sig2 = [0u8; 32];
|
||||
sig1.copy_from_slice(&bytes[..32]);
|
||||
sig2.copy_from_slice(&bytes[32..]);
|
||||
|
||||
Signature(sig1, sig2)
|
||||
}
|
||||
pub fn to_bytes(&self) -> [u8; 64] {
|
||||
let mut res = [0u8; 64];
|
||||
res[..32].copy_from_slice(&self.0);
|
||||
res[32..].copy_from_slice(&self.1);
|
||||
res
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod keys;
|
||||
pub mod msg;
|
||||
pub mod payment;
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::keys::PublicKey;
|
||||
use crate::payment::LinkPaymentData;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct InstantiateMsg {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ExecuteMsg {
|
||||
LinkPayment { data: LinkPaymentData },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum QueryMsg {
|
||||
GetPayments {
|
||||
limit: Option<u32>,
|
||||
start_after: Option<PublicKey>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct MigrateMsg {}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::keys::{PublicKey, Signature};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct Payment {
|
||||
verification_key: PublicKey,
|
||||
gateway_identity: PublicKey,
|
||||
bandwidth: u64,
|
||||
}
|
||||
|
||||
impl Payment {
|
||||
pub fn new(verification_key: PublicKey, gateway_identity: PublicKey, bandwidth: u64) -> Self {
|
||||
Payment {
|
||||
verification_key,
|
||||
gateway_identity,
|
||||
bandwidth,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verification_key(&self) -> PublicKey {
|
||||
self.verification_key
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct LinkPaymentData {
|
||||
pub verification_key: PublicKey,
|
||||
pub gateway_identity: PublicKey,
|
||||
pub bandwidth: u64,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
impl LinkPaymentData {
|
||||
pub fn new(
|
||||
verification_key: [u8; 32],
|
||||
gateway_identity: [u8; 32],
|
||||
bandwidth: u64,
|
||||
signature: [u8; 64],
|
||||
) -> Self {
|
||||
LinkPaymentData {
|
||||
verification_key: PublicKey::new(verification_key),
|
||||
gateway_identity: PublicKey::new(gateway_identity),
|
||||
bandwidth,
|
||||
signature: Signature::new(signature),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct PagedPaymentResponse {
|
||||
pub payments: Vec<Payment>,
|
||||
pub per_page: usize,
|
||||
pub start_next_after: Option<PublicKey>,
|
||||
}
|
||||
|
||||
impl PagedPaymentResponse {
|
||||
pub fn new(
|
||||
payments: Vec<Payment>,
|
||||
per_page: usize,
|
||||
start_next_after: Option<PublicKey>,
|
||||
) -> Self {
|
||||
PagedPaymentResponse {
|
||||
payments,
|
||||
per_page,
|
||||
start_next_after,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-bin-common"
|
||||
version = "0.2.0"
|
||||
version = "0.1.0"
|
||||
description = "Common code for nym binaries"
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -17,7 +17,7 @@ semver = "0.11"
|
||||
serde = { workspace = true, features = ["derive"], optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
vergen = { version = "=7.4.3", default-features = false, features = ["build", "git", "rustc", "cargo"] }
|
||||
vergen = { version = "7", default-features = false, features = ["build", "git", "rustc", "cargo"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -4,10 +4,5 @@
|
||||
use vergen::{vergen, Config};
|
||||
|
||||
fn main() {
|
||||
let mut config = Config::default();
|
||||
if std::env::var("DOCS_RS").is_ok() {
|
||||
// If we don't have access to git information, such as in a docs.rs build, don't error
|
||||
*config.git_mut().skip_if_error_mut() = true;
|
||||
}
|
||||
vergen(config).expect("failed to extract build metadata");
|
||||
vergen(Config::default()).expect("failed to extract build metadata")
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@ log = { workspace = true }
|
||||
thiserror = "1.0"
|
||||
url = "2.2"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
async-trait = { workspace = true }
|
||||
async-trait = { version = "0.1.51" }
|
||||
tokio = { version = "1.24.1", features = ["macros"] }
|
||||
|
||||
# internal
|
||||
nym-coconut-interface = { path = "../../coconut-interface" }
|
||||
nym-credentials = { path = "../../credentials" }
|
||||
coconut-interface = { path = "../../coconut-interface" }
|
||||
credentials = { path = "../../credentials" }
|
||||
nym-crypto = { path = "../../crypto" }
|
||||
gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||
nym-network-defaults = { path = "../../network-defaults" }
|
||||
@@ -47,7 +47,7 @@ features = ["net", "sync", "time"]
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
|
||||
version = "0.14"
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-credential-storage]
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.credential-storage]
|
||||
path = "../../credential-storage"
|
||||
|
||||
# wasm-only dependencies
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::error::GatewayClientError;
|
||||
use crate::wasm_mockups::Storage;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use credential_storage::storage::Storage;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(feature = "mobile")]
|
||||
@@ -22,7 +22,7 @@ use crate::wasm_mockups::StorageError;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
use nym_credential_storage::error::StorageError;
|
||||
use credential_storage::error::StorageError;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_mockups::{Client, CosmWasmClient};
|
||||
@@ -30,8 +30,8 @@ use std::str::FromStr;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use validator_client::{nyxd::CosmWasmClient, Client};
|
||||
use {
|
||||
nym_coconut_interface::Base58,
|
||||
nym_credentials::coconut::{
|
||||
coconut_interface::Base58,
|
||||
credentials::coconut::{
|
||||
bandwidth::prepare_for_spending, utils::obtain_aggregate_verification_key,
|
||||
},
|
||||
};
|
||||
@@ -42,7 +42,7 @@ use crate::wasm_mockups::PersistentStorage;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
use nym_credential_storage::PersistentStorage;
|
||||
use credential_storage::PersistentStorage;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(feature = "mobile")]
|
||||
@@ -69,17 +69,17 @@ where
|
||||
|
||||
pub async fn prepare_coconut_credential(
|
||||
&self,
|
||||
) -> Result<(nym_coconut_interface::Credential, i64), GatewayClientError> {
|
||||
) -> Result<(coconut_interface::Credential, i64), GatewayClientError> {
|
||||
let bandwidth_credential = self.storage.get_next_coconut_credential().await?;
|
||||
let voucher_value = u64::from_str(&bandwidth_credential.voucher_value)
|
||||
.map_err(|_| StorageError::InconsistentData)?;
|
||||
let voucher_info = bandwidth_credential.voucher_info.clone();
|
||||
let serial_number =
|
||||
nym_coconut_interface::Attribute::try_from_bs58(bandwidth_credential.serial_number)?;
|
||||
coconut_interface::Attribute::try_from_bs58(bandwidth_credential.serial_number)?;
|
||||
let binding_number =
|
||||
nym_coconut_interface::Attribute::try_from_bs58(bandwidth_credential.binding_number)?;
|
||||
coconut_interface::Attribute::try_from_bs58(bandwidth_credential.binding_number)?;
|
||||
let signature =
|
||||
nym_coconut_interface::Signature::try_from_bs58(bandwidth_credential.signature)?;
|
||||
coconut_interface::Signature::try_from_bs58(bandwidth_credential.signature)?;
|
||||
let epoch_id = u64::from_str(&bandwidth_credential.epoch_id)
|
||||
.map_err(|_| StorageError::InconsistentData)?;
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@ pub use crate::packet_router::{
|
||||
};
|
||||
use crate::socket_state::{PartiallyDelegated, SocketState};
|
||||
use crate::{cleanup_socket_message, try_decrypt_binary_message};
|
||||
use coconut_interface::Credential;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use gateway_requests::authentication::encrypted_address::EncryptedAddressBytes;
|
||||
use gateway_requests::iv::IV;
|
||||
use gateway_requests::registration::handshake::{client_handshake, SharedKeys};
|
||||
use gateway_requests::{BinaryRequest, ClientControlRequest, ServerResponse, PROTOCOL_VERSION};
|
||||
use log::*;
|
||||
use nym_coconut_interface::Credential;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_network_defaults::{REMAINING_BANDWIDTH_THRESHOLD, TOKENS_TO_BURN};
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
@@ -33,7 +33,7 @@ use validator_client::nyxd::CosmWasmClient;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
use nym_credential_storage::PersistentStorage;
|
||||
use credential_storage::PersistentStorage;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(feature = "mobile")]
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_mockups::StorageError;
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use credential_storage::error::StorageError;
|
||||
use gateway_requests::registration::handshake::error::HandshakeError;
|
||||
#[cfg(feature = "mobile")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use mobile_storage::StorageError;
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_credential_storage::error::StorageError;
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
use tungstenite::Error as WsError;
|
||||
@@ -31,7 +31,7 @@ pub enum GatewayClientError {
|
||||
CredentialStorageError(#[from] StorageError),
|
||||
|
||||
#[error("Coconut error - {0}")]
|
||||
CoconutError(#[from] nym_coconut_interface::CoconutError),
|
||||
CoconutError(#[from] coconut_interface::CoconutError),
|
||||
|
||||
// TODO: see if `JsValue` is a reasonable type for this
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
@@ -48,7 +48,7 @@ pub enum GatewayClientError {
|
||||
NoBandwidthControllerAvailable,
|
||||
|
||||
#[error("Credential error - {0}")]
|
||||
CredentialError(#[from] nym_credentials::error::Error),
|
||||
CredentialError(#[from] credentials::error::Error),
|
||||
|
||||
#[error("Connection was abruptly closed")]
|
||||
ConnectionAbruptlyClosed,
|
||||
|
||||
@@ -11,13 +11,13 @@ rust-version = "1.56"
|
||||
base64 = "0.13"
|
||||
colored = "2.0"
|
||||
|
||||
nym-coconut-dkg-common = { path = "../../cosmwasm-smart-contracts/coconut-dkg" }
|
||||
coconut-dkg-common = { path = "../../cosmwasm-smart-contracts/coconut-dkg" }
|
||||
nym-contracts-common = { path = "../../cosmwasm-smart-contracts/contracts-common" }
|
||||
nym-mixnet-contract-common = { path= "../../cosmwasm-smart-contracts/mixnet-contract" }
|
||||
nym-vesting-contract-common = { path= "../../cosmwasm-smart-contracts/vesting-contract" }
|
||||
nym-coconut-bandwidth-contract-common = { path= "../../cosmwasm-smart-contracts/coconut-bandwidth-contract" }
|
||||
nym-multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig-contract" }
|
||||
nym-group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" }
|
||||
coconut-bandwidth-contract-common = { path= "../../cosmwasm-smart-contracts/coconut-bandwidth-contract" }
|
||||
multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig-contract" }
|
||||
group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" }
|
||||
nym-vesting-contract = { path = "../../../contracts/vesting" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
@@ -28,18 +28,17 @@ url = { version = "2.2", features = ["serde"] }
|
||||
tokio = { version = "1.24.1", features = ["sync", "time"] }
|
||||
futures = "0.3"
|
||||
|
||||
nym-coconut-interface = { path = "../../coconut-interface" }
|
||||
coconut-interface = { path = "../../coconut-interface" }
|
||||
nym-network-defaults = { path = "../../network-defaults" }
|
||||
nym-api-requests = { path = "../../../nym-api/nym-api-requests" }
|
||||
nym-execute = { path = "../../execute" }
|
||||
|
||||
# required for nyxd-client
|
||||
# at some point it might be possible to make it wasm-compatible
|
||||
# perhaps after https://github.com/cosmos/cosmos-rust/pull/97 is resolved (and tendermint-rs is updated)
|
||||
async-trait = { workspace = true, optional = true }
|
||||
bip39 = { version = "1", features = ["rand"], optional = true }
|
||||
async-trait = { version = "0.1.51", optional = true }
|
||||
bip39 = { version = "2", features = ["rand"], optional = true }
|
||||
nym-config = { path = "../../config", optional = true }
|
||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"], optional = true}
|
||||
cosmrs = { version = "0.8.0", features = ["rpc", "bip32", "cosmwasm"], optional = true}
|
||||
cw3 = { version = "0.13.4", optional = true }
|
||||
cw4 = { version = "0.13.4", optional = true }
|
||||
prost = { version = "0.10", default-features = false, optional = true }
|
||||
@@ -47,7 +46,7 @@ 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", optional = true }
|
||||
zeroize = { version = "1.5.7", optional = true }
|
||||
nym-execute = { path = "../../execute" }
|
||||
|
||||
[dev-dependencies]
|
||||
ts-rs = "6.1.2"
|
||||
@@ -65,7 +64,6 @@ nyxd-client = [
|
||||
"sha2",
|
||||
"itertools",
|
||||
"cosmwasm-std",
|
||||
"zeroize"
|
||||
]
|
||||
generate-ts = []
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user