Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dfee78e6c0 | |||
| e17ae9dce0 | |||
| 997faeb1e6 | |||
| 565e7768e3 | |||
| 271a5fbab6 | |||
| 90a97b398e | |||
| fc2236c3c8 | |||
| c3d3164533 | |||
| fa2e0a9010 | |||
| fcc5398aab | |||
| 6403d0055b | |||
| ed48a2ddd4 | |||
| ef36c29b91 | |||
| 4025fed882 | |||
| 9aaa74204b | |||
| 9d7a6b2aec | |||
| c9489fb48e | |||
| 6c3653c128 | |||
| 31568b544c | |||
| ed76000dd0 | |||
| 0dfe1460e4 | |||
| e06087ad3f | |||
| 0a6a015987 | |||
| 3515e4e1c3 | |||
| 5ec20e5599 | |||
| 9f408d4c79 | |||
| 31233b3b68 | |||
| c4ea887319 | |||
| 6a69449e43 | |||
| 7aac01cca1 |
@@ -38,7 +38,7 @@ jobs:
|
||||
- name: install npm
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
|
||||
@@ -16,9 +16,15 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
- name: Build
|
||||
run: yarn && yarn build && yarn build:ci
|
||||
- name: Deploy branch to CI www (storybook)
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Install Yarn
|
||||
run: npm install -g yarn
|
||||
- run: yarn
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Linting for Network Explorer (eslint/prettier)
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'explorer/**'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: explorer
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-runner-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Run ESLint
|
||||
# GitHub should automatically annotate the PR
|
||||
run: yarn && yarn lint
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
continue-on-error: true
|
||||
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Matrix - Node Install
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
run: npm install
|
||||
|
||||
@@ -167,7 +167,7 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Matrix - Node Install
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
run: npm install
|
||||
|
||||
@@ -167,7 +167,7 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Matrix - Node Install
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
run: npm install
|
||||
|
||||
@@ -15,15 +15,22 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [macos-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
filename: ${{ steps.release-info.outputs.filename }}
|
||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -81,10 +88,38 @@ jobs:
|
||||
run: |
|
||||
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
- id: create-release
|
||||
name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/desktop/target/release/bundle/dmg/*.dmg
|
||||
nym-connect/desktop/target/release/bundle/macos/*.app.tar.gz*
|
||||
- id: release-info
|
||||
name: Prepare release info
|
||||
run: |
|
||||
semver="${${{ github.ref_name }}##nym-connect-}" && semver="${semver##v}"
|
||||
echo "version=$semver" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-connect_$version_x64.dmg" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/dmg/nym-connect_*_x64.dmg') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-tauri
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-tauri.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-tauri.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
|
||||
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect.app.tar.gz
|
||||
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect.app.tar.gz.sig
|
||||
version: ${{ needs.publish-tauri.outputs.version }}
|
||||
filename: ${{ needs.publish-tauri.outputs.filename }}
|
||||
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
|
||||
name: NymConnect
|
||||
category: connect
|
||||
platform: MacOS
|
||||
secrets: inherit
|
||||
|
||||
@@ -15,8 +15,15 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [custom-runner-linux]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
filename: ${{ steps.release-info.outputs.filename }}
|
||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -29,7 +36,7 @@ jobs:
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -56,10 +63,38 @@ jobs:
|
||||
path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
- id: create-release
|
||||
name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/desktop/target/release/bundle/appimage/*.AppImage
|
||||
nym-connect/desktop/target/release/bundle/appimage/*.AppImage.tar.gz*
|
||||
- id: release-info
|
||||
name: Prepare release info
|
||||
run: |
|
||||
semver="${${{ github.ref_name }}##nym-connect-}" && semver="${semver##v}"
|
||||
echo "version=$semver" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-connect_$version_amd64.AppImage" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/appimage/nym-connect_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-tauri
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-tauri.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-tauri.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
|
||||
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz
|
||||
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz.sig
|
||||
version: ${{ needs.publish-tauri.outputs.version }}
|
||||
filename: ${{ needs.publish-tauri.outputs.filename }}
|
||||
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
|
||||
name: NymConnect
|
||||
category: connect
|
||||
platform: Ubuntu
|
||||
secrets: inherit
|
||||
|
||||
@@ -15,8 +15,15 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [windows10]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
filename: ${{ steps.release-info.outputs.filename }}
|
||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||
|
||||
steps:
|
||||
- name: Clean up first
|
||||
continue-on-error: true
|
||||
@@ -42,7 +49,7 @@ jobs:
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -75,10 +82,38 @@ jobs:
|
||||
path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
- id: create-release
|
||||
name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/desktop/target/release/bundle/msi/*.msi
|
||||
nym-connect/desktop/target/release/bundle/msi/*.msi.zip*
|
||||
- id: release-info
|
||||
name: Prepare release info
|
||||
run: |
|
||||
semver="${${{ github.ref_name }}##nym-connect-}" && semver="${semver##v}"
|
||||
echo "version=$semver" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-connect_$version_x64_en-US.msi" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/msi/nym-connect_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-tauri
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-tauri.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-tauri.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
|
||||
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip
|
||||
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip.sig
|
||||
version: ${{ needs.publish-tauri.outputs.version }}
|
||||
filename: ${{ needs.publish-tauri.outputs.filename }}
|
||||
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
|
||||
name: NymConnect
|
||||
category: connect
|
||||
platform: Windows
|
||||
secrets: inherit
|
||||
|
||||
@@ -2,17 +2,17 @@ name: Publish Nym binaries
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
inputs:
|
||||
add_tokio_unstable:
|
||||
description: 'True to add RUSTFLAGS="--cfg tokio_unstable"'
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
type: boolean
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
NETWORK: mainnet
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
@@ -21,15 +21,33 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [custom-runner-linux]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
||||
client_hash: ${{ steps.binary-hashes.outputs.client_hash }}
|
||||
mixnode_hash: ${{ steps.binary-hashes.outputs.mixnode_hash }}
|
||||
gateway_hash: ${{ steps.binary-hashes.outputs.gateway_hash }}
|
||||
socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }}
|
||||
netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }}
|
||||
cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }}
|
||||
netstat_hash: ${{ steps.binary-hashes.outputs.netstat_hash }}
|
||||
client_version: ${{ steps.binary-versions.outputs.client_version }}
|
||||
mixnode_version: ${{ steps.binary-versions.outputs.mixnode_version }}
|
||||
gateway_version: ${{ steps.binary-versions.outputs.gateway_version }}
|
||||
socks5_version: ${{ steps.binary-versions.outputs.socks5_version }}
|
||||
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
|
||||
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
|
||||
netstat_version: ${{ steps.binary-versions.outputs.netstat_version }}
|
||||
|
||||
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
|
||||
run: sudo apt-get update && sudo apt-get -y install ripgrep libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
|
||||
continue-on-error: true
|
||||
|
||||
|
||||
- name: Sets env vars for tokio if set in manual dispatch inputs
|
||||
run: |
|
||||
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
|
||||
@@ -62,7 +80,8 @@ jobs:
|
||||
target/release/nym-cli
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
- id: create-release
|
||||
name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
@@ -76,3 +95,150 @@ jobs:
|
||||
target/release/nym-network-requester
|
||||
target/release/nym-network-statistics
|
||||
target/release/nym-cli
|
||||
|
||||
- id: release-info
|
||||
name: Prepare release info
|
||||
run: |
|
||||
semver="${${{ github.ref_name }}##nym-binaries-}" && semver="${semver##v}"
|
||||
echo "version=$semver" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- id: binary-hashes
|
||||
name: Generate binary hashes
|
||||
run: |
|
||||
echo "client_hash=${{ hashFiles('target/release/nym-client') }}" >> "$GITHUB_OUTPUT"
|
||||
echo "mixnode_hash=${{ hashFiles('target/release/nym-mixnode') }}" >> "$GITHUB_OUTPUT"
|
||||
echo "gateway_hash=${{ hashFiles('target/release/nym-gateway') }}" >> "$GITHUB_OUTPUT"
|
||||
echo "socks5_hash=${{ hashFiles('target/release/nym-socks5-client') }}" >> "$GITHUB_OUTPUT"
|
||||
echo "netreq_hash=${{ hashFiles('target/release/nym-network-requester') }}" >> "$GITHUB_OUTPUT"
|
||||
echo "cli_hash=${{ hashFiles('target/release/nym-cli') }}" >> "$GITHUB_OUTPUT"
|
||||
echo "netstat_hash=${{ hashFiles('target/release/nym-network-statistics') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- id: binary-versions
|
||||
name: Get binary versions
|
||||
run: |
|
||||
v=$(rg '^version = "(.*)"' -or '$1' clients/native/Cargo.toml) && echo "client_version=$v" >> "$GITHUB_OUTPUT"
|
||||
v=$(rg '^version = "(.*)"' -or '$1' mixnode/Cargo.toml) && echo "mixnode_version=$v" >> "$GITHUB_OUTPUT"
|
||||
v=$(rg '^version = "(.*)"' -or '$1' gateway/Cargo.toml) && echo "gateway_version=$v" >> "$GITHUB_OUTPUT"
|
||||
v=$(rg '^version = "(.*)"' -or '$1' clients/socks5/Cargo.toml) && echo "socks5_version=$v" >> "$GITHUB_OUTPUT"
|
||||
v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-requester/Cargo.toml) && echo "netreq_version=$v" >> "$GITHUB_OUTPUT"
|
||||
v=$(rg '^version = "(.*)"' -or '$1' tools/nym-cli/Cargo.toml) && echo "cli_version=$v" >> "$GITHUB_OUTPUT"
|
||||
v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-statistics/Cargo.toml) && echo "netstat_version=$v" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data-client:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-nym
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-nym.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-nym.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
|
||||
version: ${{ needs.publish-nym.outputs.client_version }}
|
||||
filename: nym-client
|
||||
file_hash: ${{ needs.publish-nym.outputs.client_hash }}
|
||||
name: Client
|
||||
category: binaries
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-mixnode:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-nym
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-nym.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-nym.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
|
||||
version: ${{ needs.publish-nym.outputs.mixnode_version }}
|
||||
filename: nym-mixnode
|
||||
file_hash: ${{ needs.publish-nym.outputs.mixnode_hash }}
|
||||
name: Mixnode
|
||||
category: binaries
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-gateway:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-nym
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-nym.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-nym.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
|
||||
version: ${{ needs.publish-nym.outputs.gateway_version }}
|
||||
filename: nym-gateway
|
||||
file_hash: ${{ needs.publish-nym.outputs.gateway_hash }}
|
||||
name: Gateway
|
||||
category: binaries
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-socks5:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-nym
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-nym.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-nym.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
|
||||
version: ${{ needs.publish-nym.outputs.socks5_version }}
|
||||
filename: nym-socks5-client
|
||||
file_hash: ${{ needs.publish-nym.outputs.socks5_hash }}
|
||||
name: Socks5 Client
|
||||
category: binaries
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-network-requester:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-nym
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-nym.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-nym.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
|
||||
version: ${{ needs.publish-nym.outputs.netreq_version }}
|
||||
filename: nym-network-requester
|
||||
file_hash: ${{ needs.publish-nym.outputs.netreq_hash }}
|
||||
name: Network Requester
|
||||
category: binaries
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-cli:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-nym
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-nym.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-nym.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
|
||||
version: ${{ needs.publish-nym.outputs.cli_version }}
|
||||
filename: nym-cli
|
||||
file_hash: ${{ needs.publish-nym.outputs.cli_hash }}
|
||||
name: Cli
|
||||
category: binaries
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-network-stat:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-nym
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-nym.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-nym.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
|
||||
version: ${{ needs.publish-nym.outputs.netstat_version }}
|
||||
filename: nym-network-statistics
|
||||
file_hash: ${{ needs.publish-nym.outputs.netstat_hash }}
|
||||
name: Network Statistics
|
||||
category: binaries
|
||||
secrets: inherit
|
||||
|
||||
@@ -15,15 +15,22 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [macos-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
filename: ${{ steps.release-info.outputs.filename }}
|
||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -80,11 +87,38 @@ jobs:
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
- id: create-release
|
||||
name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-wallet/target/release/bundle/dmg/*.dmg
|
||||
nym-wallet/target/release/bundle/macos/*.app.tar.gz*
|
||||
- id: release-info
|
||||
name: Prepare release info
|
||||
run: |
|
||||
semver="${${{ github.ref_name }}##nym-wallet-}" && semver="${semver##v}"
|
||||
echo "version=$semver" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-wallet_$version_x64.dmg" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/dmg/nym-wallet_*_x64.dmg') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-tauri
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-tauri.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-tauri.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
|
||||
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet.app.tar.gz
|
||||
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet.app.tar.gz.sig
|
||||
version: ${{ needs.publish-tauri.outputs.version }}
|
||||
filename: ${{ needs.publish-tauri.outputs.filename }}
|
||||
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
|
||||
name: Wallet
|
||||
category: wallet
|
||||
platform: MacOS
|
||||
secrets: inherit
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
name: Publish Nym Wallet (Ubuntu)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
@@ -14,8 +15,15 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [custom-runner-linux]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
filename: ${{ steps.release-info.outputs.filename }}
|
||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -28,7 +36,7 @@ jobs:
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -47,9 +55,37 @@ jobs:
|
||||
env:
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
- name: Upload to release based on tag name
|
||||
- id: create-release
|
||||
name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz*
|
||||
- id: release-info
|
||||
name: Prepare release info
|
||||
run: |
|
||||
semver="${${{ github.ref_name }}##nym-wallet-}" && semver="${semver##v}"
|
||||
echo "version=$semver" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-wallet_$version_amd64.AppImage" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/appimage/nym-wallet_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-tauri
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-tauri.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-tauri.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
|
||||
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz
|
||||
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz.sig
|
||||
version: ${{ needs.publish-tauri.outputs.version }}
|
||||
filename: ${{ needs.publish-tauri.outputs.filename }}
|
||||
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
|
||||
name: Wallet
|
||||
category: wallet
|
||||
platform: Ubuntu
|
||||
secrets: inherit
|
||||
|
||||
@@ -15,8 +15,15 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [windows10]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
filename: ${{ steps.release-info.outputs.filename }}
|
||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||
|
||||
steps:
|
||||
- name: Clean up first
|
||||
continue-on-error: true
|
||||
@@ -42,7 +49,7 @@ jobs:
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -75,10 +82,38 @@ jobs:
|
||||
path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
- id: create-release
|
||||
name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-wallet/target/release/bundle/msi/*.msi
|
||||
nym-wallet/target/release/bundle/msi/*.msi.zip*
|
||||
- id: release-info
|
||||
name: Prepare release info
|
||||
run: |
|
||||
semver="${${{ github.ref_name }}##nym-wallet-}" && semver="${semver##v}"
|
||||
echo "version=$semver" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-wallet_$version_x64_en-US.msi" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/msi/nym-wallet_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
needs: publish-tauri
|
||||
with:
|
||||
release_tag: ${{ github.ref_name }}
|
||||
release_id: ${{ needs.publish-tauri.outputs.release_id }}
|
||||
release_date: ${{ needs.publish-tauri.outputs.release_date }}
|
||||
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
|
||||
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
|
||||
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip
|
||||
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip.sig
|
||||
version: ${{ needs.publish-tauri.outputs.version }}
|
||||
filename: ${{ needs.publish-tauri.outputs.filename }}
|
||||
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
|
||||
name: Wallet
|
||||
category: wallet
|
||||
platform: Windows
|
||||
secrets: inherit
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Install Rust stable
|
||||
@@ -24,11 +24,7 @@ jobs:
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
working-directory: clients/webassembly
|
||||
- name: Build WASM
|
||||
run: wasm-pack build
|
||||
working-directory: clients/webassembly
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
- name: Build dependencies
|
||||
run: yarn && yarn build
|
||||
- name: Build storybook
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install yarn for building application
|
||||
run: yarn install
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
name: Push release data
|
||||
|
||||
env:
|
||||
strapi_download_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/downloaders'
|
||||
strapi_updater_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/updaters'
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
release_tag:
|
||||
required: true
|
||||
description: Release tag
|
||||
type: string
|
||||
release_id:
|
||||
required: true
|
||||
description: Release ID
|
||||
type: string
|
||||
release_date:
|
||||
required: true
|
||||
description: Release date
|
||||
type: string
|
||||
download_base_url:
|
||||
required: true
|
||||
description: Download base URL
|
||||
type: string
|
||||
changelog_url:
|
||||
required: true
|
||||
description: Changelog URL
|
||||
type: string
|
||||
archive_url:
|
||||
required: false
|
||||
description: Binary archive URL
|
||||
type: string
|
||||
sig_url:
|
||||
required: false
|
||||
description: Archive signature URL
|
||||
type: string
|
||||
version:
|
||||
required: true
|
||||
description: Release version (semver)
|
||||
type: string
|
||||
filename:
|
||||
required: true
|
||||
description: Binary file name
|
||||
type: string
|
||||
file_hash:
|
||||
required: true
|
||||
description: Binary hash (sha256)
|
||||
type: string
|
||||
name:
|
||||
required: true
|
||||
description: Name
|
||||
type: string
|
||||
category:
|
||||
required: true
|
||||
description: Category
|
||||
type: string
|
||||
platform:
|
||||
required: false
|
||||
description: Platform
|
||||
type: string
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
# ⚠ since inputs are limited to 10 max for workflow_dispatch
|
||||
# some properties were omitted
|
||||
version:
|
||||
required: true
|
||||
description: Release version (semver)
|
||||
type: string
|
||||
default: '1.0.0'
|
||||
release_id:
|
||||
required: true
|
||||
description: Release ID
|
||||
type: string
|
||||
default: '1234'
|
||||
release_date:
|
||||
required: true
|
||||
description: Release date
|
||||
type: string
|
||||
default: '2023-06-26T10:09:16Z'
|
||||
download_base_url:
|
||||
required: true
|
||||
description: Download base URL
|
||||
type: string
|
||||
default: 'https://github.com/nymtech/nym/releases/download/nym-wallet-v1.0.0'
|
||||
changelog_url:
|
||||
required: true
|
||||
description: Changelog URL
|
||||
type: string
|
||||
default: 'https://github.com/nymtech/nym/blob/nym-wallet-v1.0.0/nym-wallet/CHANGELOG.md'
|
||||
filename:
|
||||
required: true
|
||||
description: Binary file name
|
||||
type: string
|
||||
default: 'nym-wallet_1.0.0_amd64.AppImage'
|
||||
file_hash:
|
||||
required: true
|
||||
description: Binary hash (sha256)
|
||||
type: string
|
||||
default: 'xxx'
|
||||
name:
|
||||
required: true
|
||||
description: Name
|
||||
type: string
|
||||
default: 'Wallet'
|
||||
category:
|
||||
required: true
|
||||
description: Category
|
||||
default: 'wallet'
|
||||
type: choice
|
||||
options:
|
||||
- wallet
|
||||
- connect
|
||||
- binaries
|
||||
platform:
|
||||
required: false
|
||||
description: Platform
|
||||
default: 'Ubuntu'
|
||||
type: choice
|
||||
options:
|
||||
- Ubuntu
|
||||
- Windows
|
||||
- MacOS
|
||||
|
||||
jobs:
|
||||
push-download-data:
|
||||
name: Push download data to Strapi
|
||||
runs-on: custom-runner-linux
|
||||
|
||||
steps:
|
||||
- name: Release info
|
||||
run: |
|
||||
echo "version: ${{ inputs.version }}"
|
||||
echo "tag: ${{ inputs.release_tag }}"
|
||||
- id: get_sig
|
||||
name: Get sig
|
||||
if: ${{ inputs.sig_url != null }}
|
||||
run: |
|
||||
output=$(curl -LsSf ${{ inputs.sig_url }})
|
||||
echo "sig=$output" >> "$GITHUB_OUTPUT"
|
||||
- id: strapi-request
|
||||
name: Strapi request
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.strapi_download_url }}
|
||||
method: 'POST'
|
||||
bearerToken: ${{ secrets.STRAPI_API_TOKEN_RELEASES }}
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: |
|
||||
{
|
||||
"data": {
|
||||
"releaseId": "${{ inputs.release_id }}",
|
||||
"releaseDate": "${{ inputs.release_date }}",
|
||||
"downloadBaseUrl": "${{ inputs.download_base_url }}",
|
||||
"changelogUrl": "${{ inputs.changelog_url }}",
|
||||
"version": "${{ inputs.version }}",
|
||||
"filename": "${{ inputs.filename }}",
|
||||
"name": "${{ inputs.name }}",
|
||||
"category": "${{ inputs.category }}",
|
||||
"platform": "${{ inputs.platform }}",
|
||||
"sha256": "${{ inputs.file_hash }}",
|
||||
"sig": "${{ steps.get_sig.outputs.sig }}"
|
||||
}
|
||||
}
|
||||
- name: Strapi Response
|
||||
run: |
|
||||
echo ${{ steps.strapi-request.outputs.response }}
|
||||
|
||||
push-update-data:
|
||||
name: Push update data to Strapi
|
||||
runs-on: custom-runner-linux
|
||||
# only push update data for tauri apps (desktop wallet and NC)
|
||||
if: ${{ inputs.category == 'wallet' || inputs.category == 'connect' }}
|
||||
|
||||
steps:
|
||||
- name: Release info
|
||||
run: |
|
||||
echo "version: ${{ inputs.version }}"
|
||||
echo "tag: ${{ inputs.release_tag }}"
|
||||
- id: get_sig
|
||||
name: Get sig
|
||||
if: ${{ inputs.sig_url != null }}
|
||||
run: |
|
||||
output=$(curl -LsSf ${{ inputs.sig_url }})
|
||||
echo "sig=$output" >> "$GITHUB_OUTPUT"
|
||||
- id: strapi-request
|
||||
name: Strapi request
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.strapi_updater_url }}
|
||||
method: 'POST'
|
||||
bearerToken: ${{ secrets.STRAPI_API_TOKEN_RELEASES }}
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: |
|
||||
{
|
||||
"data": {
|
||||
"releaseId": "${{ inputs.release_id }}",
|
||||
"releaseDate": "${{ inputs.release_date }}",
|
||||
"downloadUrl": "${{ inputs.archive_url }}",
|
||||
"changelog": "See ${{ inputs.changelog_url }} for the changelog",
|
||||
"version": "${{ inputs.version }}",
|
||||
"filename": "${{ inputs.filename }}",
|
||||
"category": "${{ inputs.category }}",
|
||||
"platform": "${{ inputs.platform }}",
|
||||
"sha256": "${{ inputs.file_hash }}",
|
||||
"sig": "${{ steps.get_sig.outputs.sig }}"
|
||||
}
|
||||
}
|
||||
- name: Strapi Response
|
||||
run: |
|
||||
echo ${{ steps.strapi-request.outputs.response }}
|
||||
@@ -0,0 +1,19 @@
|
||||
name: Publish SDK to NPM
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: sdk/typescript/packages/sdk
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: [custom-runner-linux]
|
||||
steps:
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
@@ -1 +1 @@
|
||||
16
|
||||
18
|
||||
|
||||
@@ -11,6 +11,7 @@ on:
|
||||
- 'nym-connect/mobile/package.json'
|
||||
- 'nym-wallet/src/**'
|
||||
- 'nym-wallet/package.json'
|
||||
- 'explorer/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'ts-packages/**'
|
||||
@@ -21,6 +22,7 @@ on:
|
||||
- 'nym-connect/mobile/package.json'
|
||||
- 'nym-wallet/src/**'
|
||||
- 'nym-wallet/package.json'
|
||||
- 'explorer/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -33,7 +35,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Install Rust stable
|
||||
@@ -42,10 +44,6 @@ jobs:
|
||||
toolchain: stable
|
||||
- name: Install wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
working-directory: clients/webassembly
|
||||
- name: Build WASM
|
||||
run: wasm-pack build
|
||||
working-directory: clients/webassembly
|
||||
- name: Install
|
||||
run: yarn
|
||||
- name: Build packages
|
||||
|
||||
Generated
+10
-5
@@ -4041,8 +4041,12 @@ name = "nym-name-service-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"cw-controllers",
|
||||
"cw-utils",
|
||||
"nym-contracts-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4092,6 +4096,7 @@ dependencies = [
|
||||
"pretty_env_logger",
|
||||
"publicsuffix",
|
||||
"rand 0.7.3",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -5706,13 +5711,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.1"
|
||||
version = "1.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
|
||||
checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.7.1",
|
||||
"regex-syntax 0.7.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5732,9 +5737,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
|
||||
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
|
||||
@@ -15,9 +15,9 @@ The credential binary is still experimental software. The infrastructure for usi
|
||||
|
||||
From the project's root directory, run:
|
||||
```
|
||||
cargo build -p credential
|
||||
cargo build -p nym-credential-client
|
||||
```
|
||||
which generates the `credential` binary in `target/debug/credential`.
|
||||
which generates the `nym-credential-client` binary in `target/debug/nym-credential-client`.
|
||||
|
||||
|
||||
### Running
|
||||
@@ -25,7 +25,7 @@ which generates the `credential` binary in `target/debug/credential`.
|
||||
For example, you can get a credential worth 3 nym (3000000 unym) in a socks5 client that was already initialized like so:
|
||||
|
||||
```
|
||||
./target/debug/credential --config-env-file envs/sandbox.env --client-home-directory ~/.nym/socks5-clients/cred_client --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic $MNEMONIC --recovery-dir /tmp/recovery --amount 3000000
|
||||
./target/debug/nym-credential-client --config-env-file envs/sandbox.env --client-home-directory ~/.nym/socks5-clients/cred_client --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic $MNEMONIC --recovery-dir /tmp/recovery --amount 3000000
|
||||
```
|
||||
|
||||
More information regarding how to run the binary can be found by running it with the `--help` argument.
|
||||
|
||||
@@ -24,7 +24,6 @@ use std::net::IpAddr;
|
||||
|
||||
pub(crate) mod init;
|
||||
pub(crate) mod run;
|
||||
pub(crate) mod upgrade;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref PRETTY_BUILD_INFORMATION: String =
|
||||
@@ -51,10 +50,9 @@ pub(crate) struct Cli {
|
||||
pub(crate) enum Commands {
|
||||
/// Initialise a Nym client. Do this first!
|
||||
Init(init::Init),
|
||||
|
||||
/// Run the Nym client with provided configuration client optionally overriding set parameters
|
||||
Run(run::Run),
|
||||
/// Try to upgrade the client
|
||||
Upgrade(upgrade::Upgrade),
|
||||
|
||||
/// Generate shell completions
|
||||
Completions(ArgShell),
|
||||
@@ -81,7 +79,6 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Syn
|
||||
match &args.command {
|
||||
Commands::Init(m) => init::execute(m).await?,
|
||||
Commands::Run(m) => run::execute(m).await?,
|
||||
Commands::Upgrade(m) => upgrade::execute(m),
|
||||
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
|
||||
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::try_load_current_config;
|
||||
use clap::Args;
|
||||
use nym_bin_common::version_checker::Version;
|
||||
use std::process;
|
||||
|
||||
fn unimplemented_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||
eprintln!("Cannot perform upgrade from {config_version} to {current_version} as it hasn't been implemented yet");
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
pub(crate) struct Upgrade {
|
||||
/// Id of the nym-client we want to upgrade
|
||||
#[clap(long)]
|
||||
id: String,
|
||||
}
|
||||
|
||||
fn parse_config_version(config: &Config) -> Version {
|
||||
let version = Version::parse(&config.base.client.version).unwrap_or_else(|err| {
|
||||
eprintln!("failed to parse client version! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!(
|
||||
"Trying to upgrade from a non-released version {version}. This is not supported!"
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn parse_package_version() -> Version {
|
||||
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
||||
|
||||
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
|
||||
// however, we are not using them ourselves at the moment and hence it should be fine.
|
||||
// if we change our mind, we could easily tweak this code
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!("Trying to upgrade to a non-released version {version}. This is not supported!");
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn do_upgrade(config: Config, _args: &Upgrade, package_version: &Version) {
|
||||
let config_version = parse_config_version(&config);
|
||||
if &config_version == package_version {
|
||||
println!("You're using the most recent version!");
|
||||
return;
|
||||
}
|
||||
|
||||
unimplemented_upgrade(package_version, &config_version)
|
||||
}
|
||||
|
||||
pub(crate) fn execute(args: &Upgrade) {
|
||||
let package_version = parse_package_version();
|
||||
|
||||
let id = &args.id;
|
||||
|
||||
let existing_config = try_load_current_config(id).unwrap_or_else(|err| {
|
||||
eprintln!("failed to load existing config file! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if existing_config.base.client.version.is_empty() {
|
||||
eprintln!("the existing configuration file does not seem to contain version number.");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
do_upgrade(existing_config, args, &package_version)
|
||||
}
|
||||
@@ -24,7 +24,6 @@ use std::error::Error;
|
||||
|
||||
pub mod init;
|
||||
pub(crate) mod run;
|
||||
pub(crate) mod upgrade;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref PRETTY_BUILD_INFORMATION: String =
|
||||
@@ -55,9 +54,6 @@ pub(crate) enum Commands {
|
||||
/// Run the Nym client with provided configuration client optionally overriding set parameters
|
||||
Run(run::Run),
|
||||
|
||||
/// Try to upgrade the client
|
||||
Upgrade(upgrade::Upgrade),
|
||||
|
||||
/// Generate shell completions
|
||||
Completions(ArgShell),
|
||||
|
||||
@@ -84,7 +80,6 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Syn
|
||||
match &args.command {
|
||||
Commands::Init(m) => init::execute(m).await?,
|
||||
Commands::Run(m) => run::execute(m).await?,
|
||||
Commands::Upgrade(m) => upgrade::execute(m),
|
||||
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
|
||||
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_load_current_config;
|
||||
use crate::config::Config;
|
||||
use clap::Args;
|
||||
use nym_bin_common::version_checker::Version;
|
||||
use std::process;
|
||||
|
||||
fn unimplemented_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||
eprintln!("Cannot perform upgrade from {config_version} to {current_version} as it hasn't been implemented yet");
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
pub(crate) struct Upgrade {
|
||||
/// Id of the nym-client we want to upgrade
|
||||
#[clap(long)]
|
||||
id: String,
|
||||
}
|
||||
|
||||
fn parse_config_version(config: &Config) -> Version {
|
||||
let version = Version::parse(&config.core.base.client.version).unwrap_or_else(|err| {
|
||||
eprintln!("failed to parse client version! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!(
|
||||
"Trying to upgrade from a non-released version {version}. This is not supported!"
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn parse_package_version() -> Version {
|
||||
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
||||
|
||||
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
|
||||
// however, we are not using them ourselves at the moment and hence it should be fine.
|
||||
// if we change our mind, we could easily tweak this code
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!("Trying to upgrade to a non-released version {version}. This is not supported!");
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn do_upgrade(config: Config, _args: &Upgrade, package_version: &Version) {
|
||||
let config_version = parse_config_version(&config);
|
||||
if &config_version == package_version {
|
||||
println!("You're using the most recent version!");
|
||||
return;
|
||||
}
|
||||
|
||||
unimplemented_upgrade(package_version, &config_version)
|
||||
}
|
||||
|
||||
pub(crate) fn execute(args: &Upgrade) {
|
||||
let package_version = parse_package_version();
|
||||
|
||||
let id = &args.id;
|
||||
|
||||
let existing_config = try_load_current_config(id).unwrap_or_else(|err| {
|
||||
eprintln!("failed to load existing config file! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if existing_config.core.base.client.version.is_empty() {
|
||||
eprintln!("the existing configuration file does not seem to contain version number.");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
do_upgrade(existing_config, args, &package_version)
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
16
|
||||
18
|
||||
Generated
+4
@@ -2580,8 +2580,12 @@ name = "nym-name-service-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"cw-controllers",
|
||||
"cw-utils",
|
||||
"nym-contracts-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -4,7 +4,7 @@ use nym_contracts_common::ContractBuildInformation;
|
||||
use nym_name_service_common::{
|
||||
msg::QueryMsg as NameQueryMsg,
|
||||
response::{ConfigResponse, NamesListResponse, PagedNamesListResponse},
|
||||
Address, NameEntry, NameId,
|
||||
Address, NameId, RegisteredName,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
@@ -21,7 +21,7 @@ pub trait NameServiceQueryClient {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_name_entry(&self, name_id: NameId) -> Result<NameEntry, NyxdError> {
|
||||
async fn get_name_entry(&self, name_id: NameId) -> Result<RegisteredName, NyxdError> {
|
||||
self.query_name_service_contract(NameQueryMsg::NameId { name_id })
|
||||
.await
|
||||
}
|
||||
@@ -54,14 +54,14 @@ pub trait NameServiceQueryClient {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_all_names(&self) -> Result<Vec<NameEntry>, NyxdError> {
|
||||
async fn get_all_names(&self) -> Result<Vec<RegisteredName>, NyxdError> {
|
||||
let mut services = Vec::new();
|
||||
let mut start_after = None;
|
||||
|
||||
loop {
|
||||
let mut paged_response = self.get_names_paged(start_after.take(), None).await?;
|
||||
|
||||
let last_id = paged_response.names.last().map(|serv| serv.name_id);
|
||||
let last_id = paged_response.names.last().map(|serv| serv.id);
|
||||
services.append(&mut paged_response.names);
|
||||
|
||||
if let Some(start_after_res) = last_id {
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use async_trait::async_trait;
|
||||
use nym_name_service_common::{msg::ExecuteMsg as NameExecuteMsg, Address, NameId, NymName};
|
||||
use nym_contracts_common::signing::MessageSignature;
|
||||
use nym_name_service_common::{msg::ExecuteMsg as NameExecuteMsg, NameDetails, NameId, NymName};
|
||||
|
||||
use crate::nyxd::{
|
||||
coin::Coin, cosmwasm_client::types::ExecuteResult, error::NyxdError, Fee, NyxdClient,
|
||||
@@ -20,14 +21,17 @@ pub trait NameServiceSigningClient {
|
||||
|
||||
async fn register_name(
|
||||
&self,
|
||||
name: NymName,
|
||||
address: Address,
|
||||
name: NameDetails,
|
||||
owner_signature: MessageSignature,
|
||||
deposit: Coin,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_name_service_contract(
|
||||
fee,
|
||||
NameExecuteMsg::Register { name, address },
|
||||
NameExecuteMsg::Register {
|
||||
name,
|
||||
owner_signature,
|
||||
},
|
||||
vec![deposit],
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use clap::Parser;
|
||||
use log::{error, info};
|
||||
use nym_name_service_common::{Address, Coin, NymName};
|
||||
use nym_contracts_common::signing::MessageSignature;
|
||||
use nym_name_service_common::{Address, Coin, NameDetails, NymName};
|
||||
use nym_validator_client::nyxd::{error::NyxdError, traits::NameServiceSigningClient};
|
||||
use tap::TapFallible;
|
||||
|
||||
@@ -16,9 +17,15 @@ pub struct Args {
|
||||
#[clap(long)]
|
||||
pub nym_address: String,
|
||||
|
||||
#[clap(long)]
|
||||
pub signature: MessageSignature,
|
||||
|
||||
/// Deposit to be made to the service provider directory, in curent DENOMINATION (e.g. 'unym')
|
||||
#[clap(long)]
|
||||
pub deposit: u128,
|
||||
|
||||
#[clap(long)]
|
||||
pub identity_key: String,
|
||||
}
|
||||
|
||||
pub async fn register(args: Args, client: SigningClient) -> Result<(), NyxdError> {
|
||||
@@ -29,12 +36,17 @@ pub async fn register(args: Args, client: SigningClient) -> Result<(), NyxdError
|
||||
|
||||
let name = NymName::new(&args.name).expect("invalid name");
|
||||
let address = Address::new(&args.nym_address);
|
||||
let name = NameDetails {
|
||||
name,
|
||||
address,
|
||||
identity_key: args.identity_key,
|
||||
};
|
||||
|
||||
let denom = client.current_chain_details().mix_denom.base.as_str();
|
||||
let deposit = Coin::new(args.deposit, denom);
|
||||
|
||||
let res = client
|
||||
.register_name(name, address, deposit.into(), None)
|
||||
.register_name(name, args.signature, deposit.into(), None)
|
||||
.await
|
||||
.tap_err(|err| error!("Failed to register name: {err:#?}"))?;
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ pub async fn query(args: Args, client: &QueryClientWithNyxd) {
|
||||
table.set_header(vec!["Name Id", "Owner", "Nym Address", "Name"]);
|
||||
for name_entry in res.names {
|
||||
table.add_row(vec![
|
||||
name_entry.name_id.to_string(),
|
||||
name_entry.name.owner.to_string(),
|
||||
name_entry.id.to_string(),
|
||||
name_entry.owner.to_string(),
|
||||
name_entry.name.address.to_string(),
|
||||
name_entry.name.name.to_string(),
|
||||
]);
|
||||
|
||||
@@ -7,5 +7,9 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cosmwasm-std = { workspace = true }
|
||||
cw-controllers = { workspace = true }
|
||||
cw-utils = { workspace = true }
|
||||
nym-contracts-common = { path = "../contracts-common", version = "0.5.0" }
|
||||
schemars = "0.8"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
+19
-2
@@ -1,8 +1,10 @@
|
||||
use cosmwasm_std::{Addr, StdError};
|
||||
use cw_controllers::AdminError;
|
||||
use nym_name_service_common::{Address, NameId, NymName};
|
||||
use nym_contracts_common::signing::verifier::ApiVerifierError;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{Address, NameId, NymName};
|
||||
|
||||
#[derive(Error, Debug, PartialEq)]
|
||||
pub enum NameServiceError {
|
||||
#[error("{0}")]
|
||||
@@ -47,6 +49,21 @@ pub enum NameServiceError {
|
||||
error_message: String,
|
||||
},
|
||||
|
||||
#[error("Failed to recover ed25519 public key from its base58 representation - {0}")]
|
||||
MalformedEd25519IdentityKey(String),
|
||||
|
||||
#[error("Failed to recover ed25519 signature from its base58 representation - {0}")]
|
||||
MalformedEd25519Signature(String),
|
||||
|
||||
#[error("Provided ed25519 signature did not verify correctly")]
|
||||
InvalidEd25519Signature,
|
||||
|
||||
#[error("failed to verify message signature: {source}")]
|
||||
SignatureVerificationFailure {
|
||||
#[from]
|
||||
source: ApiVerifierError,
|
||||
},
|
||||
|
||||
#[error("duplicate entries detected for name: {name}")]
|
||||
DuplicateNames { name: NymName },
|
||||
|
||||
@@ -54,4 +71,4 @@ pub enum NameServiceError {
|
||||
NameAlreadyRegistered { name: NymName },
|
||||
}
|
||||
|
||||
pub(crate) type Result<T, E = NameServiceError> = std::result::Result<T, E>;
|
||||
pub type Result<T, E = NameServiceError> = std::result::Result<T, E>;
|
||||
@@ -1,6 +1,6 @@
|
||||
use cosmwasm_std::{Coin, Event};
|
||||
|
||||
use crate::{NameId, RegisteredName};
|
||||
use crate::RegisteredName;
|
||||
|
||||
pub enum NameEventType {
|
||||
Register,
|
||||
@@ -34,29 +34,29 @@ pub const OWNER: &str = "owner";
|
||||
|
||||
pub const DEPOSIT_REQUIRED: &str = "deposit_required";
|
||||
|
||||
pub fn new_register_event(name_id: NameId, name: RegisteredName) -> Event {
|
||||
pub fn new_register_event(name: RegisteredName) -> Event {
|
||||
Event::new(NameEventType::Register)
|
||||
.add_attribute(ACTION, NameEventType::Register)
|
||||
.add_attribute(NAME_ID, name_id.to_string())
|
||||
.add_attribute(NAME, name.name.to_string())
|
||||
.add_attribute(name.address.event_tag(), name.address.to_string())
|
||||
.add_attribute(NAME_ID, name.id.to_string())
|
||||
.add_attribute(NAME, name.name.name.to_string())
|
||||
.add_attribute(name.name.address.event_tag(), name.name.address.to_string())
|
||||
.add_attribute(OWNER, name.owner.to_string())
|
||||
}
|
||||
|
||||
pub fn new_delete_id_event(name_id: NameId, name: RegisteredName) -> Event {
|
||||
pub fn new_delete_id_event(name: RegisteredName) -> Event {
|
||||
Event::new(NameEventType::DeleteId)
|
||||
.add_attribute(ACTION, NameEventType::DeleteId)
|
||||
.add_attribute(NAME_ID, name_id.to_string())
|
||||
.add_attribute(NAME, name.name.to_string())
|
||||
.add_attribute(name.address.event_tag(), name.address.to_string())
|
||||
.add_attribute(NAME_ID, name.id.to_string())
|
||||
.add_attribute(NAME, name.name.name.to_string())
|
||||
.add_attribute(name.name.address.event_tag(), name.name.address.to_string())
|
||||
}
|
||||
|
||||
pub fn new_delete_name_event(name_id: NameId, name: RegisteredName) -> Event {
|
||||
pub fn new_delete_name_event(name: RegisteredName) -> Event {
|
||||
Event::new(NameEventType::DeleteId)
|
||||
.add_attribute(ACTION, NameEventType::DeleteName)
|
||||
.add_attribute(NAME_ID, name_id.to_string())
|
||||
.add_attribute(NAME, name.name.to_string())
|
||||
.add_attribute(name.address.event_tag(), name.address.to_string())
|
||||
.add_attribute(NAME_ID, name.id.to_string())
|
||||
.add_attribute(NAME, name.name.name.to_string())
|
||||
.add_attribute(name.name.address.event_tag(), name.name.address.to_string())
|
||||
}
|
||||
|
||||
pub fn new_update_deposit_required_event(deposit_required: Coin) -> Event {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
pub mod error;
|
||||
pub mod events;
|
||||
pub mod msg;
|
||||
pub mod response;
|
||||
pub mod signing_types;
|
||||
pub mod types;
|
||||
|
||||
// Re-export all types at the top-level
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::{Address, NameId, NymName};
|
||||
use crate::{Address, NameDetails, NameId, NymName};
|
||||
use cosmwasm_std::Coin;
|
||||
use nym_contracts_common::signing::MessageSignature;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||
@@ -22,7 +23,10 @@ pub struct MigrateMsg {}
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ExecuteMsg {
|
||||
/// Announcing a name pointing to a nym-address
|
||||
Register { name: NymName, address: Address },
|
||||
Register {
|
||||
name: NameDetails,
|
||||
owner_signature: MessageSignature,
|
||||
},
|
||||
/// Delete a name entry by id
|
||||
DeleteId { name_id: NameId },
|
||||
/// Delete a name entry by name
|
||||
@@ -38,8 +42,11 @@ impl ExecuteMsg {
|
||||
|
||||
pub fn default_memo(&self) -> String {
|
||||
match self {
|
||||
ExecuteMsg::Register { name, address } => {
|
||||
format!("registering {address} as name: {name}")
|
||||
ExecuteMsg::Register {
|
||||
name,
|
||||
owner_signature: _,
|
||||
} => {
|
||||
format!("registering {} as name: {}", name.address, name.name)
|
||||
}
|
||||
ExecuteMsg::DeleteId { name_id } => {
|
||||
format!("deleting name with id {name_id}")
|
||||
@@ -75,6 +82,9 @@ pub enum QueryMsg {
|
||||
limit: Option<u32>,
|
||||
start_after: Option<NameId>,
|
||||
},
|
||||
SigningNonce {
|
||||
address: String,
|
||||
},
|
||||
Config {},
|
||||
GetContractVersion {},
|
||||
#[serde(rename = "get_cw2_contract_version")]
|
||||
|
||||
@@ -1,36 +1,22 @@
|
||||
use crate::{msg::ExecuteMsg, NameEntry, NameId, RegisteredName};
|
||||
use crate::{NameId, RegisteredName};
|
||||
use cosmwasm_std::Coin;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Like [`NameEntry`] but since it's a response type the name is an option depending on if
|
||||
/// the name exists or not.
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct NameEntryResponse {
|
||||
pub name_id: NameId,
|
||||
pub name: Option<RegisteredName>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct NamesListResponse {
|
||||
pub names: Vec<NameEntry>,
|
||||
pub names: Vec<RegisteredName>,
|
||||
}
|
||||
|
||||
impl NamesListResponse {
|
||||
pub fn new(names: Vec<(NameId, RegisteredName)>) -> NamesListResponse {
|
||||
NamesListResponse {
|
||||
names: names
|
||||
.into_iter()
|
||||
.map(|(name_id, name)| NameEntry::new(name_id, name))
|
||||
.collect(),
|
||||
}
|
||||
pub fn new(names: Vec<RegisteredName>) -> NamesListResponse {
|
||||
NamesListResponse { names }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[NameEntry]> for NamesListResponse {
|
||||
fn from(names: &[NameEntry]) -> Self {
|
||||
impl From<&[RegisteredName]> for NamesListResponse {
|
||||
fn from(names: &[RegisteredName]) -> Self {
|
||||
NamesListResponse {
|
||||
names: names.to_vec(),
|
||||
}
|
||||
@@ -40,21 +26,17 @@ impl From<&[NameEntry]> for NamesListResponse {
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct PagedNamesListResponse {
|
||||
pub names: Vec<NameEntry>,
|
||||
pub names: Vec<RegisteredName>,
|
||||
pub per_page: usize,
|
||||
pub start_next_after: Option<NameId>,
|
||||
}
|
||||
|
||||
impl PagedNamesListResponse {
|
||||
pub fn new(
|
||||
names: Vec<(NameId, RegisteredName)>,
|
||||
names: Vec<RegisteredName>,
|
||||
per_page: usize,
|
||||
start_next_after: Option<NameId>,
|
||||
) -> PagedNamesListResponse {
|
||||
let names = names
|
||||
.into_iter()
|
||||
.map(|(name_id, name)| NameEntry::new(name_id, name))
|
||||
.collect();
|
||||
PagedNamesListResponse {
|
||||
names,
|
||||
per_page,
|
||||
@@ -68,12 +50,3 @@ impl PagedNamesListResponse {
|
||||
pub struct ConfigResponse {
|
||||
pub deposit_required: Coin,
|
||||
}
|
||||
|
||||
impl From<RegisteredName> for ExecuteMsg {
|
||||
fn from(name: RegisteredName) -> Self {
|
||||
ExecuteMsg::Register {
|
||||
name: name.name,
|
||||
address: name.address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
use cosmwasm_std::{Addr, Coin};
|
||||
use nym_contracts_common::signing::{
|
||||
ContractMessageContent, MessageType, Nonce, SignableMessage, SigningPurpose,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::NameDetails;
|
||||
|
||||
pub type SignableNameRegisterMsg = SignableMessage<ContractMessageContent<NameRegister>>;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct NameRegister {
|
||||
name: NameDetails,
|
||||
}
|
||||
|
||||
impl SigningPurpose for NameRegister {
|
||||
fn message_type() -> MessageType {
|
||||
MessageType::new("name-register")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn construct_name_register_sign_payload(
|
||||
nonce: Nonce,
|
||||
sender: Addr,
|
||||
deposit: Coin,
|
||||
name: NameDetails,
|
||||
) -> SignableNameRegisterMsg {
|
||||
let payload = NameRegister { name };
|
||||
let proxy = None;
|
||||
let content = ContractMessageContent::new(sender, proxy, vec![deposit], payload);
|
||||
SignableMessage::new(nonce, content)
|
||||
}
|
||||
@@ -1,24 +1,48 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use cosmwasm_std::{Addr, Coin};
|
||||
use nym_contracts_common::IdentityKey;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// The directory of services are indexed by [`ServiceId`].
|
||||
/// The directory of names are indexed by [`NameId`].
|
||||
pub type NameId = u32;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, JsonSchema)]
|
||||
pub struct RegisteredName {
|
||||
/// Unique id assigned to the registerd name.
|
||||
pub id: NameId,
|
||||
|
||||
/// The registerd name details.
|
||||
pub name: NameDetails,
|
||||
|
||||
/// name owner.
|
||||
pub owner: Addr,
|
||||
|
||||
/// Block height at which the name was added.
|
||||
pub block_height: u64,
|
||||
|
||||
/// The deposit used to announce the name.
|
||||
pub deposit: Coin,
|
||||
}
|
||||
|
||||
impl RegisteredName {
|
||||
// Shortcut for getting the actual name
|
||||
pub fn entry(&self) -> &NymName {
|
||||
&self.name.name
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, JsonSchema)]
|
||||
pub struct NameDetails {
|
||||
/// The name pointing to the nym address
|
||||
pub name: NymName,
|
||||
/// The address of the service.
|
||||
|
||||
/// The address of the name alias.
|
||||
pub address: Address,
|
||||
/// Service owner.
|
||||
pub owner: Addr,
|
||||
/// Block height at which the service was added.
|
||||
pub block_height: u64,
|
||||
/// The deposit used to announce the service.
|
||||
pub deposit: Coin,
|
||||
|
||||
/// The identity key of the registered name.
|
||||
pub identity_key: IdentityKey,
|
||||
}
|
||||
|
||||
/// String representation of a nym address, which is of the form
|
||||
@@ -68,6 +92,7 @@ pub enum NymNameError {
|
||||
InvalidName,
|
||||
}
|
||||
|
||||
/// Defines what names are allowed
|
||||
fn is_valid_name_char(c: char) -> bool {
|
||||
// Normal lowercase letters
|
||||
(c.is_alphabetic() && c.is_lowercase())
|
||||
@@ -98,20 +123,6 @@ impl Display for NymName {
|
||||
}
|
||||
}
|
||||
|
||||
/// [`RegisterdName`] together with the assigned [`NameId`].
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct NameEntry {
|
||||
pub name_id: NameId,
|
||||
pub name: RegisteredName,
|
||||
}
|
||||
|
||||
impl NameEntry {
|
||||
pub fn new(name_id: NameId, name: RegisteredName) -> Self {
|
||||
Self { name_id, name }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::NymName;
|
||||
|
||||
@@ -7,9 +7,9 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cosmwasm-std = { workspace = true }
|
||||
cw-controllers = { workspace = true }
|
||||
cw-utils = { workspace = true }
|
||||
nym-contracts-common = { path = "../contracts-common", version = "0.5.0" }
|
||||
schemars = "0.8"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
cw-utils = { workspace = true }
|
||||
cw-controllers = { workspace = true }
|
||||
|
||||
@@ -78,7 +78,7 @@ impl SocksRequest {
|
||||
where
|
||||
R: AsyncRead + Unpin,
|
||||
{
|
||||
log::info!("read from stream socks5");
|
||||
log::trace!("read from stream socks5");
|
||||
|
||||
let mut packet = [0u8; 4];
|
||||
// Read a byte from the stream and determine the version being requested
|
||||
|
||||
@@ -30,7 +30,7 @@ enum TaskError {
|
||||
}
|
||||
|
||||
// TODO: possibly we should create a `Status` trait instead of reusing `Error`
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[derive(thiserror::Error, Debug, PartialEq, Eq)]
|
||||
pub enum TaskStatus {
|
||||
#[error("Ready")]
|
||||
Ready,
|
||||
|
||||
Generated
+9
-2
@@ -1411,6 +1411,7 @@ name = "nym-name-service"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bs58",
|
||||
"cosmwasm-std",
|
||||
"cw-controllers",
|
||||
"cw-multi-test",
|
||||
@@ -1418,8 +1419,10 @@ dependencies = [
|
||||
"cw-utils",
|
||||
"cw2",
|
||||
"nym-contracts-common",
|
||||
"nym-crypto",
|
||||
"nym-name-service-common",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.2.2",
|
||||
"rstest",
|
||||
"semver",
|
||||
"serde",
|
||||
@@ -1432,8 +1435,12 @@ name = "nym-name-service-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"cw-controllers",
|
||||
"cw-utils",
|
||||
"nym-contracts-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1646,9 +1653,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.52"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
|
||||
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ edition = "2021"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
bs58 = "0.4.0"
|
||||
cosmwasm-std = { workspace = true }
|
||||
cw-controllers = { workspace = true }
|
||||
cw-storage-plus = { workspace = true }
|
||||
@@ -24,5 +25,7 @@ vergen = { version = "=7.4.3", default-features = false, features = ["build", "g
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.40"
|
||||
cw-multi-test = { workspace = true }
|
||||
nym-crypto = { path = "../../common/crypto", features = ["asymmetric", "rand"] }
|
||||
rand = "0.8.5"
|
||||
rand_chacha = "0.2"
|
||||
rstest = "0.17.0"
|
||||
|
||||
@@ -14,3 +14,5 @@ pub const NAMES_PK_NAMESPACE: &str = "nanames";
|
||||
pub const NAMES_OWNER_IDX_NAMESPACE: &str = "naowner";
|
||||
pub const NAMES_ADDRESS_IDX_NAMESPACE: &str = "naaddress";
|
||||
pub const NAMES_NAME_IDX_NAMESPACE: &str = "naname";
|
||||
|
||||
pub const SIGNING_NONCES_NAMESPACE: &str = "nasn";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
error::{NameServiceError, Result},
|
||||
state::{self, Config},
|
||||
NameServiceError, Result,
|
||||
};
|
||||
use cosmwasm_std::{to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response};
|
||||
use nym_name_service_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
|
||||
@@ -72,7 +72,10 @@ pub fn execute(
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, NameServiceError> {
|
||||
match msg {
|
||||
ExecuteMsg::Register { name, address } => execute::register(deps, env, info, name, address),
|
||||
ExecuteMsg::Register {
|
||||
name,
|
||||
owner_signature,
|
||||
} => execute::register(deps, env, info, name, owner_signature),
|
||||
ExecuteMsg::DeleteId { name_id } => execute::delete_id(deps, info, name_id),
|
||||
ExecuteMsg::DeleteName { name } => execute::delete_name(deps, info, name),
|
||||
ExecuteMsg::UpdateDepositRequired { deposit_required } => {
|
||||
@@ -90,6 +93,9 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<Binary> {
|
||||
QueryMsg::All { limit, start_after } => {
|
||||
to_binary(&query::query_all_paged(deps, limit, start_after)?)
|
||||
}
|
||||
QueryMsg::SigningNonce { address } => {
|
||||
to_binary(&query::query_current_signing_nonce(deps, address)?)
|
||||
}
|
||||
QueryMsg::Config {} => to_binary(&query::query_config(deps)?),
|
||||
QueryMsg::GetContractVersion {} => to_binary(&query::query_contract_version()),
|
||||
QueryMsg::GetCW2ContractVersion {} => to_binary(&cw2::get_contract_version(deps.storage)?),
|
||||
@@ -102,16 +108,19 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::test_helpers::{
|
||||
assert::{assert_config, assert_empty, assert_name, assert_names, assert_not_found},
|
||||
fixture::name_fixture,
|
||||
helpers::{get_attribute, nyms},
|
||||
assert::{
|
||||
assert_config, assert_current_nonce, assert_empty, assert_name, assert_names,
|
||||
assert_not_found,
|
||||
},
|
||||
fixture::new_name_details_with_sign,
|
||||
helpers::{get_attribute, nyms, test_rng},
|
||||
};
|
||||
|
||||
use cosmwasm_std::{
|
||||
testing::{mock_dependencies, mock_env, mock_info},
|
||||
Addr, Coin,
|
||||
};
|
||||
use nym_name_service_common::{msg::ExecuteMsg, NameEntry, NameId};
|
||||
use nym_name_service_common::{msg::ExecuteMsg, NameId, RegisteredName};
|
||||
|
||||
const DENOM: &str = "unym";
|
||||
|
||||
@@ -135,23 +144,28 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn register_fails_incorrect_deposit() {
|
||||
fn register_fails_deposit_too_small() {
|
||||
let mut rng = test_rng();
|
||||
let mut deps = mock_dependencies();
|
||||
let msg = InstantiateMsg::new(nyms(100));
|
||||
let info = mock_info("creator", &[]);
|
||||
let admin = info.sender.clone();
|
||||
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
|
||||
assert_eq!(res.messages.len(), 0);
|
||||
|
||||
// Register
|
||||
let msg: ExecuteMsg = name_fixture().into();
|
||||
let owner = name_fixture().owner.to_string();
|
||||
let deposit = nyms(99);
|
||||
let owner = "steve";
|
||||
let (name, owner_signature) =
|
||||
new_name_details_with_sign(deps.as_mut(), &mut rng, "foo", "address", owner, deposit);
|
||||
let msg = ExecuteMsg::Register {
|
||||
name,
|
||||
owner_signature,
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
execute(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(&owner, &[nyms(99)]),
|
||||
mock_info(owner, &[nyms(99)]),
|
||||
msg.clone()
|
||||
)
|
||||
.unwrap_err(),
|
||||
@@ -161,34 +175,135 @@ mod tests {
|
||||
}
|
||||
);
|
||||
|
||||
// Since we signed for 99unym deposit.
|
||||
assert_eq!(
|
||||
execute(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(&owner, &[nyms(101)]),
|
||||
mock_info(owner, &[nyms(100)]),
|
||||
msg
|
||||
)
|
||||
.unwrap_err(),
|
||||
NameServiceError::InvalidEd25519Signature,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn register_fails_deposit_too_large() {
|
||||
let mut rng = test_rng();
|
||||
let mut deps = mock_dependencies();
|
||||
let msg = InstantiateMsg::new(nyms(100));
|
||||
let info = mock_info("creator", &[]);
|
||||
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
|
||||
assert_eq!(res.messages.len(), 0);
|
||||
|
||||
let deposit = nyms(101);
|
||||
let owner = "steve";
|
||||
let (name, owner_signature) =
|
||||
new_name_details_with_sign(deps.as_mut(), &mut rng, "foo", "address", owner, deposit);
|
||||
let msg = ExecuteMsg::Register {
|
||||
name,
|
||||
owner_signature,
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
execute(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(owner, &[nyms(101)]),
|
||||
msg.clone()
|
||||
)
|
||||
.unwrap_err(),
|
||||
NameServiceError::TooLargeDeposit {
|
||||
funds: 101u128.into(),
|
||||
deposit_required: 100u128.into(),
|
||||
}
|
||||
);
|
||||
|
||||
assert_config(deps.as_ref(), &admin, Coin::new(100, DENOM));
|
||||
assert_empty(deps.as_ref());
|
||||
// Since we signed for 101unym deposit.
|
||||
assert_eq!(
|
||||
execute(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(owner, &[nyms(100)]),
|
||||
msg
|
||||
)
|
||||
.unwrap_err(),
|
||||
NameServiceError::InvalidEd25519Signature,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn register_success() {
|
||||
fn register_fails_owner_mismatch() {
|
||||
let mut rng = test_rng();
|
||||
let mut deps = mock_dependencies();
|
||||
let msg = InstantiateMsg::new(nyms(100));
|
||||
let info = mock_info("creator", &[]);
|
||||
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
|
||||
assert_eq!(res.messages.len(), 0);
|
||||
|
||||
// Setup
|
||||
let deposit = nyms(100);
|
||||
let owner = "steve";
|
||||
let (name, owner_signature) = new_name_details_with_sign(
|
||||
deps.as_mut(),
|
||||
&mut rng,
|
||||
"my-name",
|
||||
"my-address",
|
||||
owner,
|
||||
deposit,
|
||||
);
|
||||
|
||||
// Register
|
||||
let msg: ExecuteMsg = name_fixture().into();
|
||||
let msg = ExecuteMsg::Register {
|
||||
name,
|
||||
owner_signature,
|
||||
};
|
||||
assert_eq!(
|
||||
execute(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("timmy", &[nyms(100)]),
|
||||
msg.clone(),
|
||||
)
|
||||
.unwrap_err(),
|
||||
NameServiceError::InvalidEd25519Signature,
|
||||
);
|
||||
assert!(execute(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("steve", &[nyms(100)]),
|
||||
msg
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn register_success() {
|
||||
let mut rng = test_rng();
|
||||
let mut deps = mock_dependencies();
|
||||
let msg = InstantiateMsg::new(nyms(100));
|
||||
let info = mock_info("creator", &[]);
|
||||
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
|
||||
assert_eq!(res.messages.len(), 0);
|
||||
|
||||
// Setup
|
||||
let deposit = nyms(100);
|
||||
let owner = "steve";
|
||||
let (name, owner_signature) = new_name_details_with_sign(
|
||||
deps.as_mut(),
|
||||
&mut rng,
|
||||
"my-name",
|
||||
"my-address",
|
||||
owner,
|
||||
deposit.clone(),
|
||||
);
|
||||
|
||||
// Register
|
||||
let msg = ExecuteMsg::Register {
|
||||
name: name.clone(),
|
||||
owner_signature,
|
||||
};
|
||||
let info = mock_info("steve", &[nyms(100)]);
|
||||
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
|
||||
|
||||
@@ -198,17 +313,24 @@ mod tests {
|
||||
assert_eq!(id, expected_id);
|
||||
assert_eq!(
|
||||
get_attribute(&res, "register", "name"),
|
||||
"my-service".to_string()
|
||||
"my-name".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
get_attribute(&res, "register", "nym_address"),
|
||||
"client_id.client_key@gateway_id".to_string()
|
||||
"my-address".to_string()
|
||||
);
|
||||
|
||||
// Check that the nonce has been incremented, but only for the owner
|
||||
assert_current_nonce(deps.as_ref(), &Addr::unchecked("steve"), 1);
|
||||
assert_current_nonce(deps.as_ref(), &Addr::unchecked("timmy"), 0);
|
||||
|
||||
// The expected registered name
|
||||
let expected_name = NameEntry {
|
||||
name_id: expected_id,
|
||||
name: name_fixture(),
|
||||
let expected_name = RegisteredName {
|
||||
id: expected_id,
|
||||
name,
|
||||
owner: Addr::unchecked(owner),
|
||||
block_height: 12345,
|
||||
deposit,
|
||||
};
|
||||
assert_names(deps.as_ref(), &[expected_name.clone()]);
|
||||
assert_name(deps.as_ref(), &expected_name);
|
||||
@@ -216,6 +338,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn delete() {
|
||||
let mut rng = test_rng();
|
||||
let mut deps = mock_dependencies();
|
||||
let msg = InstantiateMsg::new(Coin::new(100, "unym"));
|
||||
let info = mock_info("creator", &[]);
|
||||
@@ -223,16 +346,31 @@ mod tests {
|
||||
assert_eq!(res.messages.len(), 0);
|
||||
|
||||
// Register
|
||||
let msg: ExecuteMsg = name_fixture().into();
|
||||
let deposit = nyms(100);
|
||||
let steve = "steve";
|
||||
let (name, owner_signature) = new_name_details_with_sign(
|
||||
deps.as_mut(),
|
||||
&mut rng,
|
||||
"my-name",
|
||||
"my-address",
|
||||
steve,
|
||||
deposit.clone(),
|
||||
);
|
||||
let msg = ExecuteMsg::Register {
|
||||
name: name.clone(),
|
||||
owner_signature,
|
||||
};
|
||||
let info_steve = mock_info("steve", &[nyms(100)]);
|
||||
assert_eq!(info_steve.sender, name_fixture().owner);
|
||||
execute(deps.as_mut(), mock_env(), info_steve, msg).unwrap();
|
||||
execute(deps.as_mut(), mock_env(), info_steve.clone(), msg).unwrap();
|
||||
|
||||
// The expected registerd name
|
||||
let expected_id = 1;
|
||||
let expected_name = NameEntry {
|
||||
name_id: expected_id,
|
||||
name: name_fixture(),
|
||||
let expected_name = RegisteredName {
|
||||
id: expected_id,
|
||||
name,
|
||||
owner: Addr::unchecked(steve),
|
||||
block_height: 12345,
|
||||
deposit,
|
||||
};
|
||||
assert_names(deps.as_ref(), &[expected_name]);
|
||||
|
||||
@@ -248,12 +386,8 @@ mod tests {
|
||||
|
||||
// Removing an non-existent name will fail
|
||||
let msg = ExecuteMsg::delete_id(expected_id + 1);
|
||||
let info_owner = MessageInfo {
|
||||
sender: name_fixture().owner,
|
||||
funds: vec![],
|
||||
};
|
||||
assert_eq!(
|
||||
execute(deps.as_mut(), mock_env(), info_owner.clone(), msg).unwrap_err(),
|
||||
execute(deps.as_mut(), mock_env(), info_steve.clone(), msg).unwrap_err(),
|
||||
NameServiceError::NotFound {
|
||||
name_id: expected_id + 1
|
||||
}
|
||||
@@ -261,7 +395,7 @@ mod tests {
|
||||
|
||||
// Remove as correct owner succeeds
|
||||
let msg = ExecuteMsg::delete_id(expected_id);
|
||||
let res = execute(deps.as_mut(), mock_env(), info_owner, msg).unwrap();
|
||||
let res = execute(deps.as_mut(), mock_env(), info_steve, msg).unwrap();
|
||||
assert_eq!(
|
||||
get_attribute(&res, "delete_id", "name_id"),
|
||||
expected_id.to_string()
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
use crate::{
|
||||
constants::{MAX_NUMBER_OF_NAMES_FOR_ADDRESS, MAX_NUMBER_OF_NAMES_PER_OWNER},
|
||||
error::{NameServiceError, Result},
|
||||
state,
|
||||
state, NameServiceError, Result,
|
||||
};
|
||||
use cosmwasm_std::{Addr, BankMsg, Coin, Deps, DepsMut, Env, MessageInfo, Response, Uint128};
|
||||
use nym_contracts_common::{
|
||||
signing::{MessageSignature, Verifier},
|
||||
IdentityKey,
|
||||
};
|
||||
use nym_name_service_common::{
|
||||
events::{
|
||||
new_delete_id_event, new_delete_name_event, new_register_event,
|
||||
new_update_deposit_required_event,
|
||||
},
|
||||
Address, NameId, NymName, RegisteredName,
|
||||
signing_types::construct_name_register_sign_payload,
|
||||
Address, NameDetails, NameId, NymName, RegisteredName,
|
||||
};
|
||||
|
||||
use super::query;
|
||||
@@ -86,17 +90,54 @@ fn return_deposit(name_to_delete: &RegisteredName) -> BankMsg {
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_register_signature(
|
||||
deps: Deps<'_>,
|
||||
sender: Addr,
|
||||
deposit: Coin,
|
||||
name: NameDetails,
|
||||
signature: MessageSignature,
|
||||
) -> Result<()> {
|
||||
// recover the public key
|
||||
let public_key = decode_ed25519_identity_key(&name.identity_key)?;
|
||||
|
||||
// reconstruct the payload
|
||||
let nonce = state::get_signing_nonce(deps.storage, sender.clone())?;
|
||||
|
||||
let msg = construct_name_register_sign_payload(nonce, sender, deposit, name);
|
||||
|
||||
if deps.api.verify_message(msg, signature, &public_key)? {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(NameServiceError::InvalidEd25519Signature)
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_ed25519_identity_key(encoded: &IdentityKey) -> Result<[u8; 32]> {
|
||||
let mut public_key = [0u8; 32];
|
||||
let used = bs58::decode(encoded)
|
||||
.into(&mut public_key)
|
||||
.map_err(|err| NameServiceError::MalformedEd25519IdentityKey(err.to_string()))?;
|
||||
|
||||
if used != 32 {
|
||||
return Err(NameServiceError::MalformedEd25519IdentityKey(
|
||||
"Too few bytes provided for the public key".into(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(public_key)
|
||||
}
|
||||
|
||||
/// Register a new name. It will be assigned a new name id.
|
||||
pub fn register(
|
||||
deps: DepsMut,
|
||||
env: Env,
|
||||
info: MessageInfo,
|
||||
name: NymName,
|
||||
address: Address,
|
||||
name: NameDetails,
|
||||
owner_signature: MessageSignature,
|
||||
) -> Result<Response> {
|
||||
ensure_name_not_exists(deps.as_ref(), &name)?;
|
||||
ensure_name_not_exists(deps.as_ref(), &name.name)?;
|
||||
ensure_max_names_per_owner(deps.as_ref(), info.sender.clone())?;
|
||||
ensure_max_names_per_address(deps.as_ref(), address.clone())?;
|
||||
ensure_max_names_per_address(deps.as_ref(), name.address.clone())?;
|
||||
|
||||
let deposit_required = state::deposit_required(deps.storage)?;
|
||||
let denom = deposit_required.denom.clone();
|
||||
@@ -104,16 +145,29 @@ pub fn register(
|
||||
.map_err(|err| NameServiceError::DepositRequired { source: err })?;
|
||||
ensure_correct_deposit(will_deposit, deposit_required.amount)?;
|
||||
|
||||
let deposit = Coin::new(will_deposit.u128(), denom);
|
||||
|
||||
verify_register_signature(
|
||||
deps.as_ref(),
|
||||
info.sender.clone(),
|
||||
deposit.clone(),
|
||||
name.clone(),
|
||||
owner_signature,
|
||||
)?;
|
||||
|
||||
state::increment_signing_nonce(deps.storage, info.sender.clone())?;
|
||||
|
||||
let id = state::next_name_id_counter(deps.storage)?;
|
||||
let new_name = RegisteredName {
|
||||
address,
|
||||
id,
|
||||
name,
|
||||
owner: info.sender,
|
||||
block_height: env.block.height,
|
||||
deposit: Coin::new(will_deposit.u128(), denom),
|
||||
deposit,
|
||||
};
|
||||
let name_id = state::names::save(deps.storage, &new_name)?;
|
||||
state::names::save(deps.storage, &new_name)?;
|
||||
|
||||
Ok(Response::new().add_event(new_register_event(name_id, new_name)))
|
||||
Ok(Response::new().add_event(new_register_event(new_name)))
|
||||
}
|
||||
|
||||
/// Delete an exsisting name.
|
||||
@@ -127,23 +181,20 @@ pub fn delete_id(deps: DepsMut, info: MessageInfo, name_id: NameId) -> Result<Re
|
||||
|
||||
Ok(Response::new()
|
||||
.add_message(return_deposit_msg)
|
||||
.add_event(new_delete_id_event(name_id, name_to_delete)))
|
||||
.add_event(new_delete_id_event(name_to_delete)))
|
||||
}
|
||||
|
||||
/// Delete an existing name by name.
|
||||
pub(crate) fn delete_name(deps: DepsMut, info: MessageInfo, name: NymName) -> Result<Response> {
|
||||
let name_to_delete = query::query_name(deps.as_ref(), name)?;
|
||||
ensure_sender_authorized(info, &name_to_delete.name)?;
|
||||
ensure_sender_authorized(info, &name_to_delete)?;
|
||||
|
||||
state::names::remove_id(deps.storage, name_to_delete.name_id)?;
|
||||
let return_deposit_msg = return_deposit(&name_to_delete.name);
|
||||
state::names::remove_id(deps.storage, name_to_delete.id)?;
|
||||
let return_deposit_msg = return_deposit(&name_to_delete);
|
||||
|
||||
Ok(Response::new()
|
||||
.add_message(return_deposit_msg)
|
||||
.add_event(new_delete_name_event(
|
||||
name_to_delete.name_id,
|
||||
name_to_delete.name,
|
||||
)))
|
||||
.add_event(new_delete_name_event(name_to_delete)))
|
||||
}
|
||||
|
||||
/// Update the deposit required to register new names
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
use cosmwasm_std::Deps;
|
||||
use nym_contracts_common::ContractBuildInformation;
|
||||
use nym_contracts_common::{signing::Nonce, ContractBuildInformation};
|
||||
use nym_name_service_common::{
|
||||
response::{ConfigResponse, NamesListResponse, PagedNamesListResponse},
|
||||
Address, NameEntry, NameId, NymName,
|
||||
Address, NameId, NymName, RegisteredName,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::Result,
|
||||
state::{self, names::PagedLoad},
|
||||
Result,
|
||||
};
|
||||
|
||||
pub fn query_id(deps: Deps, name_id: NameId) -> Result<NameEntry> {
|
||||
let name = state::names::load_id(deps.storage, name_id)?;
|
||||
Ok(NameEntry { name_id, name })
|
||||
pub fn query_id(deps: Deps, name_id: NameId) -> Result<RegisteredName> {
|
||||
state::names::load_id(deps.storage, name_id)
|
||||
}
|
||||
|
||||
pub fn query_owner(deps: Deps, owner: String) -> Result<NamesListResponse> {
|
||||
@@ -26,9 +25,8 @@ pub fn query_address(deps: Deps, address: Address) -> Result<NamesListResponse>
|
||||
Ok(NamesListResponse::new(names))
|
||||
}
|
||||
|
||||
pub fn query_name(deps: Deps, name: NymName) -> Result<NameEntry> {
|
||||
state::names::load_name_entry(deps.storage, &name)
|
||||
.map(|(name_id, name)| NameEntry::new(name_id, name))
|
||||
pub fn query_name(deps: Deps, name: NymName) -> Result<RegisteredName> {
|
||||
state::names::load_name(deps.storage, &name)
|
||||
}
|
||||
|
||||
pub fn query_all_paged(
|
||||
@@ -44,6 +42,11 @@ pub fn query_all_paged(
|
||||
Ok(PagedNamesListResponse::new(names, limit, start_next_after))
|
||||
}
|
||||
|
||||
pub fn query_current_signing_nonce(deps: Deps<'_>, address: String) -> Result<Nonce> {
|
||||
let address = deps.api.addr_validate(&address)?;
|
||||
state::get_signing_nonce(deps.storage, address)
|
||||
}
|
||||
|
||||
pub fn query_config(deps: Deps) -> Result<ConfigResponse> {
|
||||
let config = state::load_config(deps.storage)?;
|
||||
Ok(config.into())
|
||||
|
||||
@@ -1,445 +0,0 @@
|
||||
//! Integration tests using cw-multi-test.
|
||||
|
||||
use cosmwasm_std::Addr;
|
||||
use nym_name_service_common::{
|
||||
response::{ConfigResponse, PagedNamesListResponse},
|
||||
Address, NameEntry, NymName, RegisteredName,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
constants::NAME_DEFAULT_RETRIEVAL_LIMIT,
|
||||
error::NameServiceError,
|
||||
test_helpers::{fixture::name_entry, helpers::nyms, test_setup::TestSetup},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn instantiate_contract() {
|
||||
TestSetup::new();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn query_config() {
|
||||
assert_eq!(
|
||||
TestSetup::new().query_config(),
|
||||
ConfigResponse {
|
||||
deposit_required: nyms(100),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn register_and_query_name() {
|
||||
let mut setup = TestSetup::new();
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: None,
|
||||
}
|
||||
);
|
||||
|
||||
// Register a first name
|
||||
let owner = Addr::unchecked("owner");
|
||||
let name = NymName::new("steves-server").unwrap();
|
||||
let nym_address = Address::new("nym-address");
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert_eq!(setup.balance(&owner), nyms(250));
|
||||
setup.register(name.clone(), nym_address.clone(), owner.clone());
|
||||
|
||||
// Deposit is deposited to contract and deducted from owners's balance
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(setup.balance(&owner), nyms(150));
|
||||
|
||||
// We can query the full name list
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![NameEntry {
|
||||
name_id: 1,
|
||||
name: RegisteredName {
|
||||
address: nym_address.clone(),
|
||||
name: name.clone(),
|
||||
owner: owner.clone(),
|
||||
block_height: 12345,
|
||||
deposit: nyms(100),
|
||||
},
|
||||
}],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(1),
|
||||
}
|
||||
);
|
||||
|
||||
// ... and we can query by id
|
||||
assert_eq!(
|
||||
setup.query_id(1),
|
||||
NameEntry {
|
||||
name_id: 1,
|
||||
name: RegisteredName {
|
||||
address: nym_address.clone(),
|
||||
name: name.clone(),
|
||||
owner: owner.clone(),
|
||||
block_height: 12345,
|
||||
deposit: nyms(100),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Register a second name
|
||||
let owner2 = Addr::unchecked("owner2");
|
||||
let name2 = NymName::new("another_server").unwrap();
|
||||
let nym_address2 = Address::new("nymAddress2");
|
||||
setup.register(name2.clone(), nym_address2.clone(), owner2.clone());
|
||||
|
||||
assert_eq!(setup.contract_balance(), nyms(200));
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
name_entry(1, name, nym_address, owner),
|
||||
name_entry(2, name2, nym_address2, owner2)
|
||||
],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(2),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cant_register_a_name_without_funds() {
|
||||
let mut setup = TestSetup::new();
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert_eq!(setup.balance("owner"), nyms(250));
|
||||
setup.register(
|
||||
NymName::new("my_name").unwrap(),
|
||||
Address::new("nymAddress"),
|
||||
Addr::unchecked("owner"),
|
||||
);
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(setup.balance("owner"), nyms(150));
|
||||
setup.register(
|
||||
NymName::new("my_name2").unwrap(),
|
||||
Address::new("nymAddress"),
|
||||
Addr::unchecked("owner"),
|
||||
);
|
||||
assert_eq!(setup.contract_balance(), nyms(200));
|
||||
assert_eq!(setup.balance("owner"), nyms(50));
|
||||
let res = setup
|
||||
.try_register(
|
||||
NymName::new("my_name3").unwrap(),
|
||||
Address::new("nymAddress"),
|
||||
Addr::unchecked("owner"),
|
||||
)
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
res.downcast::<cosmwasm_std::StdError>().unwrap(),
|
||||
cosmwasm_std::StdError::Overflow {
|
||||
source: cosmwasm_std::OverflowError::new(
|
||||
cosmwasm_std::OverflowOperation::Sub,
|
||||
"50",
|
||||
"100"
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_name() {
|
||||
let mut setup = TestSetup::new();
|
||||
setup.register(
|
||||
NymName::new("my_name").unwrap(),
|
||||
Address::new("nymAddress"),
|
||||
Addr::unchecked("owner"),
|
||||
);
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(setup.balance("owner"), nyms(150));
|
||||
assert!(!setup.query_all().names.is_empty());
|
||||
setup.delete(1, Addr::unchecked("owner"));
|
||||
|
||||
// Deleting the name returns the deposit to the owner
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert_eq!(setup.balance("owner"), nyms(250));
|
||||
assert!(setup.query_all().names.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_owner_can_delete_name() {
|
||||
let mut setup = TestSetup::new();
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
setup.register(
|
||||
NymName::new("name").unwrap(),
|
||||
Address::new("nymAddress"),
|
||||
Addr::unchecked("owner"),
|
||||
);
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert!(!setup.query_all().names.is_empty());
|
||||
|
||||
let delete_resp = setup
|
||||
.try_delete(1, Addr::unchecked("not_owner"))
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(
|
||||
delete_resp.downcast::<NameServiceError>().unwrap(),
|
||||
NameServiceError::Unauthorized {
|
||||
sender: Addr::unchecked("not_owner")
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cant_delete_name_that_does_not_exist() {
|
||||
let mut setup = TestSetup::new();
|
||||
setup.register(
|
||||
NymName::new("foo").unwrap(),
|
||||
Address::new("nymAddress"),
|
||||
Addr::unchecked("owner"),
|
||||
);
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert!(!setup.query_all().names.is_empty());
|
||||
|
||||
let delete_resp = setup.try_delete(0, Addr::unchecked("owner")).unwrap_err();
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(
|
||||
delete_resp.downcast::<NameServiceError>().unwrap(),
|
||||
NameServiceError::NotFound { name_id: 0 }
|
||||
);
|
||||
|
||||
let delete_resp = setup.try_delete(2, Addr::unchecked("owner")).unwrap_err();
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(
|
||||
delete_resp.downcast::<NameServiceError>().unwrap(),
|
||||
NameServiceError::NotFound { name_id: 2 }
|
||||
);
|
||||
|
||||
assert!(!setup.query_all().names.is_empty());
|
||||
setup.delete(1, Addr::unchecked("owner"));
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert!(setup.query_all().names.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cant_register_the_same_name_multiple_times() {
|
||||
let mut setup = TestSetup::new();
|
||||
|
||||
setup.register(
|
||||
NymName::new("name").unwrap(),
|
||||
Address::new("nymAddress"),
|
||||
Addr::unchecked("owner"),
|
||||
);
|
||||
let resp = setup
|
||||
.try_register(
|
||||
NymName::new("name").unwrap(),
|
||||
Address::new("nymAddress"),
|
||||
Addr::unchecked("owner"),
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
resp.downcast::<NameServiceError>().unwrap(),
|
||||
NameServiceError::NameAlreadyRegistered {
|
||||
name: NymName::new("name").unwrap()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_register_multiple_names_for_the_same_nym_address() {
|
||||
let mut setup = TestSetup::new();
|
||||
let name1 = NymName::new("name1").unwrap();
|
||||
let name2 = NymName::new("name2").unwrap();
|
||||
let address = Address::new("nymaddress");
|
||||
let owner = Addr::unchecked("owner");
|
||||
|
||||
setup.register(name1.clone(), address.clone(), owner.clone());
|
||||
setup.register(name2.clone(), address.clone(), owner.clone());
|
||||
|
||||
assert_eq!(
|
||||
setup.query_all().names,
|
||||
vec![
|
||||
name_entry(1, name1, address.clone(), owner.clone()),
|
||||
name_entry(2, name2, address, owner)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn register_multiple_names_and_deleting_by_name() {
|
||||
let mut setup = TestSetup::new();
|
||||
let owner1 = Addr::unchecked("wealthy_owner_1");
|
||||
let owner2 = Addr::unchecked("wealthy_owner_2");
|
||||
let nym_address1 = Address::new("nymaddress1");
|
||||
let nym_address2 = Address::new("nymaddress2");
|
||||
let name1 = NymName::new("name1").unwrap();
|
||||
let name2 = NymName::new("name2").unwrap();
|
||||
let name3 = NymName::new("name3").unwrap();
|
||||
let name4 = NymName::new("name4").unwrap();
|
||||
let name5 = NymName::new("name5").unwrap();
|
||||
|
||||
// We register the same address three times, but with different owners
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert_eq!(setup.balance(&owner1), nyms(1000));
|
||||
setup.register(name1.clone(), nym_address1.clone(), owner1.clone());
|
||||
setup.register(name2.clone(), nym_address1.clone(), owner1.clone());
|
||||
setup.register(name3.clone(), nym_address2.clone(), owner1.clone());
|
||||
setup.register(name4.clone(), nym_address1.clone(), owner2.clone());
|
||||
setup.register(name5.clone(), nym_address2.clone(), owner2.clone());
|
||||
|
||||
assert_eq!(setup.contract_balance(), nyms(500));
|
||||
assert_eq!(setup.balance(&owner1), nyms(700));
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
name_entry(1, name1.clone(), nym_address1.clone(), owner1.clone()),
|
||||
name_entry(2, name2.clone(), nym_address1.clone(), owner1.clone()),
|
||||
name_entry(3, name3.clone(), nym_address2.clone(), owner1.clone()),
|
||||
name_entry(4, name4.clone(), nym_address1.clone(), owner2.clone()),
|
||||
name_entry(5, name5.clone(), nym_address2.clone(), owner2.clone()),
|
||||
],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(5),
|
||||
}
|
||||
);
|
||||
|
||||
setup.delete_name(name1, owner1.clone());
|
||||
|
||||
assert_eq!(setup.contract_balance(), nyms(400));
|
||||
assert_eq!(setup.balance(&owner1), nyms(800));
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
name_entry(2, name2, nym_address1.clone(), owner1.clone()),
|
||||
name_entry(3, name3, nym_address2.clone(), owner1),
|
||||
name_entry(4, name4, nym_address1, owner2.clone()),
|
||||
name_entry(5, name5, nym_address2, owner2),
|
||||
],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(5),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_paging() {
|
||||
let mut setup = TestSetup::new();
|
||||
let owner1 = Addr::unchecked("wealthy_owner_1");
|
||||
let owner2 = Addr::unchecked("wealthy_owner_2");
|
||||
let nym_address1 = Address::new("nymAddress1");
|
||||
let nym_address2 = Address::new("nymAddress2");
|
||||
let name1 = NymName::new("name1").unwrap();
|
||||
let name2 = NymName::new("name2").unwrap();
|
||||
let name3 = NymName::new("name3").unwrap();
|
||||
let name4 = NymName::new("name4").unwrap();
|
||||
let name5 = NymName::new("name5").unwrap();
|
||||
|
||||
// We register the same address three times, but with different owners
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert_eq!(setup.balance(&owner1), nyms(1000));
|
||||
setup.register(name1.clone(), nym_address1.clone(), owner1.clone());
|
||||
setup.register(name2.clone(), nym_address1.clone(), owner1.clone());
|
||||
setup.register(name3.clone(), nym_address2.clone(), owner1.clone());
|
||||
setup.register(name4.clone(), nym_address1.clone(), owner2.clone());
|
||||
setup.register(name5.clone(), nym_address2.clone(), owner2.clone());
|
||||
|
||||
assert_eq!(setup.contract_balance(), nyms(500));
|
||||
assert_eq!(setup.balance(&owner1), nyms(700));
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
name_entry(1, name1.clone(), nym_address1.clone(), owner1.clone()),
|
||||
name_entry(2, name2.clone(), nym_address1.clone(), owner1.clone()),
|
||||
name_entry(3, name3.clone(), nym_address2.clone(), owner1.clone()),
|
||||
name_entry(4, name4.clone(), nym_address1.clone(), owner2.clone()),
|
||||
name_entry(5, name5, nym_address2.clone(), owner2.clone()),
|
||||
],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(5),
|
||||
}
|
||||
);
|
||||
|
||||
setup.delete_name(name1, owner1.clone());
|
||||
|
||||
assert_eq!(
|
||||
setup.query_all_with_limit(Some(2), None),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
name_entry(2, name2, nym_address1.clone(), owner1.clone()),
|
||||
name_entry(3, name3.clone(), nym_address2.clone(), owner1.clone()),
|
||||
],
|
||||
per_page: 2,
|
||||
start_next_after: Some(3),
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
setup.query_all_with_limit(Some(2), Some(2)),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
name_entry(3, name3, nym_address2, owner1),
|
||||
name_entry(4, name4, nym_address1, owner2),
|
||||
],
|
||||
per_page: 2,
|
||||
start_next_after: Some(4),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn name_id_is_not_resused_when_deleting_and_then_adding_a_new_names() {
|
||||
let mut setup = TestSetup::new();
|
||||
setup.register(
|
||||
NymName::new("myname1").unwrap(),
|
||||
Address::new("nymAddress1"),
|
||||
Addr::unchecked("owner1"),
|
||||
);
|
||||
setup.register(
|
||||
NymName::new("myname2").unwrap(),
|
||||
Address::new("nymAddress2"),
|
||||
Addr::unchecked("owner2"),
|
||||
);
|
||||
setup.register(
|
||||
NymName::new("myname3").unwrap(),
|
||||
Address::new("nymAddress3"),
|
||||
Addr::unchecked("owner3"),
|
||||
);
|
||||
|
||||
setup.delete(1, Addr::unchecked("owner1"));
|
||||
setup.delete(3, Addr::unchecked("owner3"));
|
||||
|
||||
assert_eq!(
|
||||
setup.query_all().names,
|
||||
vec![name_entry(
|
||||
2,
|
||||
NymName::new("myname2").unwrap(),
|
||||
Address::new("nymAddress2"),
|
||||
Addr::unchecked("owner2")
|
||||
)]
|
||||
);
|
||||
|
||||
setup.register(
|
||||
NymName::new("myname4").unwrap(),
|
||||
Address::new("nymAddress4"),
|
||||
Addr::unchecked("owner4"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
setup.query_all().names,
|
||||
vec![
|
||||
name_entry(
|
||||
2,
|
||||
NymName::new("myname2").unwrap(),
|
||||
Address::new("nymAddress2"),
|
||||
Addr::unchecked("owner2")
|
||||
),
|
||||
name_entry(
|
||||
4,
|
||||
NymName::new("myname4").unwrap(),
|
||||
Address::new("nymAddress4"),
|
||||
Addr::unchecked("owner4")
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
use cosmwasm_std::Addr;
|
||||
use nym_name_service_common::{response::PagedNamesListResponse, Address, NymName};
|
||||
use rstest::rstest;
|
||||
|
||||
use crate::{
|
||||
constants::NAME_DEFAULT_RETRIEVAL_LIMIT,
|
||||
test_helpers::{fixture::new_name, helpers::nyms},
|
||||
NameServiceError,
|
||||
};
|
||||
|
||||
use super::test_setup::TestSetup;
|
||||
|
||||
#[rstest::fixture]
|
||||
fn setup() -> TestSetup {
|
||||
TestSetup::new()
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn delete_name(mut setup: TestSetup) {
|
||||
setup.sign_and_register(
|
||||
&NymName::new("my_name").unwrap(),
|
||||
&Address::new("address"),
|
||||
&Addr::unchecked("owner"),
|
||||
&nyms(100),
|
||||
);
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(setup.balance("owner"), nyms(150));
|
||||
assert!(!setup.query_all().names.is_empty());
|
||||
setup.delete(1, Addr::unchecked("owner"));
|
||||
|
||||
// Deleting the name returns the deposit to the owner
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert_eq!(setup.balance("owner"), nyms(250));
|
||||
assert!(setup.query_all().names.is_empty());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn only_owner_can_delete_name(mut setup: TestSetup) {
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
setup.sign_and_register(
|
||||
&NymName::new("name").unwrap(),
|
||||
&Address::new("nymAddress"),
|
||||
&Addr::unchecked("owner"),
|
||||
&nyms(100),
|
||||
);
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert!(!setup.query_all().names.is_empty());
|
||||
|
||||
let delete_resp = setup
|
||||
.try_delete(1, Addr::unchecked("not_owner"))
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(
|
||||
delete_resp.downcast::<NameServiceError>().unwrap(),
|
||||
NameServiceError::Unauthorized {
|
||||
sender: Addr::unchecked("not_owner")
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn cant_delete_name_that_does_not_exist(mut setup: TestSetup) {
|
||||
setup.sign_and_register(
|
||||
&NymName::new("foo").unwrap(),
|
||||
&Address::new("nymAddress"),
|
||||
&Addr::unchecked("owner"),
|
||||
&nyms(100),
|
||||
);
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert!(!setup.query_all().names.is_empty());
|
||||
|
||||
let delete_resp = setup.try_delete(0, Addr::unchecked("owner")).unwrap_err();
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(
|
||||
delete_resp.downcast::<NameServiceError>().unwrap(),
|
||||
NameServiceError::NotFound { name_id: 0 }
|
||||
);
|
||||
|
||||
let delete_resp = setup.try_delete(2, Addr::unchecked("owner")).unwrap_err();
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(
|
||||
delete_resp.downcast::<NameServiceError>().unwrap(),
|
||||
NameServiceError::NotFound { name_id: 2 }
|
||||
);
|
||||
|
||||
assert!(!setup.query_all().names.is_empty());
|
||||
setup.delete(1, Addr::unchecked("owner"));
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert!(setup.query_all().names.is_empty());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn register_multiple_names_and_deleting_by_name(mut setup: TestSetup) {
|
||||
let owner1 = Addr::unchecked("wealthy_owner_1");
|
||||
let owner2 = Addr::unchecked("wealthy_owner_2");
|
||||
let address1 = Address::new("address1");
|
||||
let address2 = Address::new("address2");
|
||||
let name1 = NymName::new("name1").unwrap();
|
||||
let name2 = NymName::new("name2").unwrap();
|
||||
let name3 = NymName::new("name3").unwrap();
|
||||
let name4 = NymName::new("name4").unwrap();
|
||||
let name5 = NymName::new("name5").unwrap();
|
||||
|
||||
// We register the same address three times, but with different owners
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert_eq!(setup.balance(&owner1), nyms(1000));
|
||||
let s1 = setup.sign_and_register(&name1, &address1, &owner1, &nyms(100));
|
||||
let s2 = setup.sign_and_register(&name2, &address1, &owner1, &nyms(100));
|
||||
let s3 = setup.sign_and_register(&name3, &address2, &owner1, &nyms(100));
|
||||
let s4 = setup.sign_and_register(&name4, &address1, &owner2, &nyms(100));
|
||||
let s5 = setup.sign_and_register(&name5, &address2, &owner2, &nyms(100));
|
||||
|
||||
assert_eq!(setup.contract_balance(), nyms(500));
|
||||
assert_eq!(setup.balance(&owner1), nyms(700));
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
new_name(1, &name1, &address1, &owner1, s1.identity_key()),
|
||||
new_name(2, &name2, &address1, &owner1, s2.identity_key()),
|
||||
new_name(3, &name3, &address2, &owner1, s3.identity_key()),
|
||||
new_name(4, &name4, &address1, &owner2, s4.identity_key()),
|
||||
new_name(5, &name5, &address2, &owner2, s5.identity_key()),
|
||||
],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(5),
|
||||
}
|
||||
);
|
||||
|
||||
setup.delete_name(name1, owner1.clone());
|
||||
|
||||
assert_eq!(setup.contract_balance(), nyms(400));
|
||||
assert_eq!(setup.balance(&owner1), nyms(800));
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
new_name(2, &name2, &address1, &owner1, s2.identity_key()),
|
||||
new_name(3, &name3, &address2, &owner1, s3.identity_key()),
|
||||
new_name(4, &name4, &address1, &owner2, s4.identity_key()),
|
||||
new_name(5, &name5, &address2, &owner2, s5.identity_key()),
|
||||
],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(5),
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
//! Integration tests using cw-multi-test.
|
||||
|
||||
mod delete;
|
||||
mod name_id;
|
||||
mod query;
|
||||
mod register;
|
||||
mod test_name;
|
||||
mod test_setup;
|
||||
|
||||
#[test]
|
||||
fn instantiate_contract() {
|
||||
test_setup::TestSetup::new();
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
use cosmwasm_std::Addr;
|
||||
use nym_name_service_common::{Address, NymName};
|
||||
|
||||
use crate::test_helpers::{fixture::new_name, helpers::nyms};
|
||||
|
||||
use super::test_setup::TestSetup;
|
||||
|
||||
#[test]
|
||||
fn name_id_is_not_resused_when_deleting_and_then_adding_a_new_names() {
|
||||
let mut setup = TestSetup::new();
|
||||
setup.sign_and_register(
|
||||
&NymName::new("myname1").unwrap(),
|
||||
&Address::new("nymAddress1"),
|
||||
&Addr::unchecked("owner1"),
|
||||
&nyms(100),
|
||||
);
|
||||
let s2 = setup.sign_and_register(
|
||||
&NymName::new("myname2").unwrap(),
|
||||
&Address::new("nymAddress2"),
|
||||
&Addr::unchecked("owner2"),
|
||||
&nyms(100),
|
||||
);
|
||||
setup.sign_and_register(
|
||||
&NymName::new("myname3").unwrap(),
|
||||
&Address::new("nymAddress3"),
|
||||
&Addr::unchecked("owner3"),
|
||||
&nyms(100),
|
||||
);
|
||||
|
||||
setup.delete(1, Addr::unchecked("owner1"));
|
||||
setup.delete(3, Addr::unchecked("owner3"));
|
||||
|
||||
assert_eq!(
|
||||
setup.query_all().names,
|
||||
vec![new_name(
|
||||
2,
|
||||
&NymName::new("myname2").unwrap(),
|
||||
&Address::new("nymAddress2"),
|
||||
&Addr::unchecked("owner2"),
|
||||
s2.identity_key(),
|
||||
)]
|
||||
);
|
||||
|
||||
let s4 = setup.sign_and_register(
|
||||
&NymName::new("myname4").unwrap(),
|
||||
&Address::new("nymAddress4"),
|
||||
&Addr::unchecked("owner4"),
|
||||
&nyms(100),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
setup.query_all().names,
|
||||
vec![
|
||||
new_name(
|
||||
2,
|
||||
&NymName::new("myname2").unwrap(),
|
||||
&Address::new("nymAddress2"),
|
||||
&Addr::unchecked("owner2"),
|
||||
s2.identity_key(),
|
||||
),
|
||||
new_name(
|
||||
4,
|
||||
&NymName::new("myname4").unwrap(),
|
||||
&Address::new("nymAddress4"),
|
||||
&Addr::unchecked("owner4"),
|
||||
s4.identity_key(),
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
use cosmwasm_std::Addr;
|
||||
use nym_name_service_common::{
|
||||
response::{ConfigResponse, PagedNamesListResponse},
|
||||
Address, NymName,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
constants::NAME_DEFAULT_RETRIEVAL_LIMIT,
|
||||
test_helpers::{fixture::new_name, helpers::nyms},
|
||||
};
|
||||
|
||||
use super::test_setup::TestSetup;
|
||||
|
||||
#[test]
|
||||
fn query_config() {
|
||||
assert_eq!(
|
||||
TestSetup::new().query_config(),
|
||||
ConfigResponse {
|
||||
deposit_required: nyms(100),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_paging() {
|
||||
let mut setup = TestSetup::new();
|
||||
let owner1 = Addr::unchecked("wealthy_owner_1");
|
||||
let owner2 = Addr::unchecked("wealthy_owner_2");
|
||||
let address1 = Address::new("nymAddress1");
|
||||
let address2 = Address::new("nymAddress2");
|
||||
let name1 = NymName::new("name1").unwrap();
|
||||
let name2 = NymName::new("name2").unwrap();
|
||||
let name3 = NymName::new("name3").unwrap();
|
||||
let name4 = NymName::new("name4").unwrap();
|
||||
let name5 = NymName::new("name5").unwrap();
|
||||
|
||||
// We register the same address three times, but with different owners
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert_eq!(setup.balance(&owner1), nyms(1000));
|
||||
let s1 = setup.sign_and_register(&name1, &address1, &owner1, &nyms(100));
|
||||
let s2 = setup.sign_and_register(&name2, &address1, &owner1, &nyms(100));
|
||||
let s3 = setup.sign_and_register(&name3, &address2, &owner1, &nyms(100));
|
||||
let s4 = setup.sign_and_register(&name4, &address1, &owner2, &nyms(100));
|
||||
let s5 = setup.sign_and_register(&name5, &address2, &owner2, &nyms(100));
|
||||
|
||||
assert_eq!(setup.contract_balance(), nyms(500));
|
||||
assert_eq!(setup.balance(&owner1), nyms(700));
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
new_name(1, &name1, &address1, &owner1, s1.identity_key()),
|
||||
new_name(2, &name2, &address1, &owner1, s2.identity_key()),
|
||||
new_name(3, &name3, &address2, &owner1, s3.identity_key()),
|
||||
new_name(4, &name4, &address1, &owner2, s4.identity_key()),
|
||||
new_name(5, &name5, &address2, &owner2, s5.identity_key()),
|
||||
],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(5),
|
||||
}
|
||||
);
|
||||
|
||||
setup.delete_name(name1, owner1.clone());
|
||||
|
||||
assert_eq!(
|
||||
setup.query_all_with_limit(Some(2), None),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
new_name(2, &name2, &address1, &owner1, s2.identity_key()),
|
||||
new_name(3, &name3, &address2, &owner1, s3.identity_key()),
|
||||
],
|
||||
per_page: 2,
|
||||
start_next_after: Some(3),
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
setup.query_all_with_limit(Some(2), Some(2)),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
new_name(3, &name3, &address2, &owner1, s3.identity_key()),
|
||||
new_name(4, &name4, &address1, &owner2, s4.identity_key()),
|
||||
],
|
||||
per_page: 2,
|
||||
start_next_after: Some(4),
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
use cosmwasm_std::Addr;
|
||||
use nym_name_service_common::{
|
||||
error::NameServiceError, response::PagedNamesListResponse, Address, NameDetails, NymName,
|
||||
RegisteredName,
|
||||
};
|
||||
use rstest::rstest;
|
||||
|
||||
use crate::{
|
||||
constants::NAME_DEFAULT_RETRIEVAL_LIMIT,
|
||||
test_helpers::{fixture::new_name, helpers::nyms},
|
||||
};
|
||||
|
||||
use super::test_setup::TestSetup;
|
||||
|
||||
#[rstest::fixture]
|
||||
fn setup() -> TestSetup {
|
||||
TestSetup::new()
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn basic_register(mut setup: TestSetup) {
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: None,
|
||||
}
|
||||
);
|
||||
|
||||
// Register a first name
|
||||
let owner = Addr::unchecked("owner");
|
||||
let name = NymName::new("steves-server").unwrap();
|
||||
let nym_address = Address::new("nym-address");
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert_eq!(setup.balance(&owner), nyms(250));
|
||||
assert_eq!(setup.query_signing_nonce(owner.to_string()), 0);
|
||||
|
||||
let reg_name = setup.new_name(&name, &nym_address);
|
||||
let payload = setup.payload_to_sign(&owner, &nyms(100), ®_name.name);
|
||||
let reg_name = reg_name.sign(payload);
|
||||
setup.register(®_name, &owner);
|
||||
|
||||
// Deposit is deposited to contract and deducted from owners's balance
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(setup.balance(&owner), nyms(150));
|
||||
|
||||
// The signing nonce has been incremented
|
||||
assert_eq!(setup.query_signing_nonce(owner.to_string()), 1);
|
||||
|
||||
// We can query the full name list
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![RegisteredName {
|
||||
id: 1,
|
||||
name: NameDetails {
|
||||
name: name.clone(),
|
||||
address: nym_address.clone(),
|
||||
identity_key: reg_name.identity_key().to_string(),
|
||||
},
|
||||
owner: owner.clone(),
|
||||
block_height: 12345,
|
||||
deposit: nyms(100),
|
||||
}],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(1),
|
||||
}
|
||||
);
|
||||
|
||||
// ... and we can query by id
|
||||
assert_eq!(
|
||||
setup.query_id(1),
|
||||
RegisteredName {
|
||||
id: 1,
|
||||
name: reg_name.details().clone(),
|
||||
owner: owner.clone(),
|
||||
block_height: 12345,
|
||||
deposit: nyms(100),
|
||||
}
|
||||
);
|
||||
|
||||
// Register a second name
|
||||
let owner2 = Addr::unchecked("owner2");
|
||||
let name2 = NymName::new("another_server").unwrap();
|
||||
let nym_address2 = Address::new("nymAddress2");
|
||||
let reg_name2 = setup.new_signed_name(&name2, &nym_address2, &owner2, &nyms(100));
|
||||
setup.register(®_name2, &owner2);
|
||||
|
||||
assert_eq!(setup.contract_balance(), nyms(200));
|
||||
assert_eq!(
|
||||
setup.query_all(),
|
||||
PagedNamesListResponse {
|
||||
names: vec![
|
||||
new_name(1, &name, &nym_address, &owner, reg_name.identity_key()),
|
||||
new_name(2, &name2, &nym_address2, &owner2, reg_name2.identity_key()),
|
||||
],
|
||||
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(2),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn register_fails_when_owner_mismatch(mut setup: TestSetup) {
|
||||
let owner = Addr::unchecked("owner");
|
||||
let name = NymName::new("steves-server").unwrap();
|
||||
let nym_address = Address::new("nym-address");
|
||||
let reg_name = setup.new_signed_name(&name, &nym_address, &owner, &nyms(100));
|
||||
let res = setup
|
||||
.try_register(®_name, &Addr::unchecked("owner2"))
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
res.downcast::<NameServiceError>().unwrap(),
|
||||
NameServiceError::InvalidEd25519Signature
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn signing_nonce_is_increased_when_registering(mut setup: TestSetup) {
|
||||
let owner1 = Addr::unchecked("owner1");
|
||||
let owner2 = Addr::unchecked("owner2");
|
||||
|
||||
assert_eq!(setup.query_signing_nonce(owner1.to_string()), 0);
|
||||
assert_eq!(setup.query_signing_nonce(owner2.to_string()), 0);
|
||||
|
||||
setup.sign_and_register(
|
||||
&NymName::new("myname1").unwrap(),
|
||||
&Address::new("address1"),
|
||||
&owner1,
|
||||
&nyms(100),
|
||||
);
|
||||
|
||||
assert_eq!(setup.query_signing_nonce(owner1.to_string()), 1);
|
||||
assert_eq!(setup.query_signing_nonce(owner2.to_string()), 0);
|
||||
|
||||
setup.sign_and_register(
|
||||
&NymName::new("myname2").unwrap(),
|
||||
&Address::new("address2"),
|
||||
&owner2,
|
||||
&nyms(100),
|
||||
);
|
||||
|
||||
assert_eq!(setup.query_signing_nonce(owner1.to_string()), 1);
|
||||
assert_eq!(setup.query_signing_nonce(owner2.to_string()), 1);
|
||||
|
||||
setup.sign_and_register(
|
||||
&NymName::new("myname3").unwrap(),
|
||||
&Address::new("address3"),
|
||||
&owner2,
|
||||
&nyms(100),
|
||||
);
|
||||
|
||||
assert_eq!(setup.query_signing_nonce(owner1.to_string()), 1);
|
||||
assert_eq!(setup.query_signing_nonce(owner2.to_string()), 2);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn creating_two_names_in_a_row_without_announcing_fails(mut setup: TestSetup) {
|
||||
let owner = Addr::unchecked("wealthy_owner_1");
|
||||
let name1 = NymName::new("steves-server1").unwrap();
|
||||
let name2 = NymName::new("steves-server2").unwrap();
|
||||
let address1 = Address::new("nymAddress1");
|
||||
let address2 = Address::new("nymAddress2");
|
||||
let deposit = nyms(100);
|
||||
|
||||
let s1 = setup.new_signed_name(&name1, &address1, &owner, &deposit);
|
||||
|
||||
// This second name will be signed with the same nonce
|
||||
let s2 = setup.new_signed_name(&name2, &address2, &owner, &deposit);
|
||||
|
||||
// Announce the first service works, and this increments the nonce
|
||||
setup.register(&s1, &owner);
|
||||
|
||||
// Now the nonce has been incremented, and the signature will not match
|
||||
let resp: NameServiceError = setup
|
||||
.try_register(&s2, &owner)
|
||||
.unwrap_err()
|
||||
.downcast()
|
||||
.unwrap();
|
||||
assert_eq!(resp, NameServiceError::InvalidEd25519Signature,);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn cant_register_a_name_without_funds(mut setup: TestSetup) {
|
||||
assert_eq!(setup.contract_balance(), nyms(0));
|
||||
assert_eq!(setup.balance("owner"), nyms(250));
|
||||
let name1 = setup.new_signed_name(
|
||||
&NymName::new("my_name").unwrap(),
|
||||
&Address::new("nymAddress"),
|
||||
&Addr::unchecked("owner"),
|
||||
&nyms(100),
|
||||
);
|
||||
setup.register(&name1, &Addr::unchecked("owner"));
|
||||
assert_eq!(setup.contract_balance(), nyms(100));
|
||||
assert_eq!(setup.balance("owner"), nyms(150));
|
||||
|
||||
let name2 = setup.new_signed_name(
|
||||
&NymName::new("my_name2").unwrap(),
|
||||
&Address::new("nymAddress"),
|
||||
&Addr::unchecked("owner"),
|
||||
&nyms(100),
|
||||
);
|
||||
setup.register(&name2, &Addr::unchecked("owner"));
|
||||
assert_eq!(setup.contract_balance(), nyms(200));
|
||||
assert_eq!(setup.balance("owner"), nyms(50));
|
||||
let name3 = setup.new_signed_name(
|
||||
&NymName::new("my_name3").unwrap(),
|
||||
&Address::new("nymAddress"),
|
||||
&Addr::unchecked("owner"),
|
||||
&nyms(100),
|
||||
);
|
||||
let res = setup
|
||||
.try_register(&name3, &Addr::unchecked("owner"))
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
res.downcast::<cosmwasm_std::StdError>().unwrap(),
|
||||
cosmwasm_std::StdError::Overflow {
|
||||
source: cosmwasm_std::OverflowError::new(
|
||||
cosmwasm_std::OverflowOperation::Sub,
|
||||
"50",
|
||||
"100"
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn cant_register_the_same_name_multiple_times(mut setup: TestSetup) {
|
||||
let name1 = setup.new_signed_name(
|
||||
&NymName::new("name").unwrap(),
|
||||
&Address::new("nymAddress"),
|
||||
&Addr::unchecked("owner"),
|
||||
&nyms(100),
|
||||
);
|
||||
setup.register(&name1, &Addr::unchecked("owner"));
|
||||
let resp = setup
|
||||
.try_register(&name1, &Addr::unchecked("owner"))
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
resp.downcast::<NameServiceError>().unwrap(),
|
||||
NameServiceError::NameAlreadyRegistered {
|
||||
name: NymName::new("name").unwrap()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn can_register_multiple_names_for_the_same_nym_address(mut setup: TestSetup) {
|
||||
let name1 = NymName::new("name1").unwrap();
|
||||
let name2 = NymName::new("name2").unwrap();
|
||||
let address = Address::new("nymaddress");
|
||||
let owner = Addr::unchecked("owner");
|
||||
|
||||
let reg_name1 = setup.new_signed_name(&name1, &address, &owner, &nyms(100));
|
||||
setup.register(®_name1, &owner);
|
||||
let reg_name2 = setup.new_signed_name(&name2, &address, &owner, &nyms(100));
|
||||
setup.register(®_name2, &owner);
|
||||
|
||||
assert_eq!(
|
||||
setup.query_all().names,
|
||||
vec![
|
||||
new_name(1, &name1, &address, &owner, reg_name1.identity_key()),
|
||||
new_name(2, &name2, &address, &owner, reg_name2.identity_key()),
|
||||
],
|
||||
);
|
||||
}
|
||||
//
|
||||
@@ -0,0 +1,75 @@
|
||||
use nym_contracts_common::{signing::MessageSignature, IdentityKey};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_name_service_common::{
|
||||
signing_types::SignableNameRegisterMsg, Address, NameDetails, NymName,
|
||||
};
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
|
||||
use crate::test_helpers::signing::ed25519_sign_message;
|
||||
|
||||
pub struct TestName {
|
||||
pub name: NameDetails,
|
||||
pub keys: identity::KeyPair,
|
||||
pub rng: ChaCha20Rng,
|
||||
}
|
||||
|
||||
impl TestName {
|
||||
pub fn new(rng: &mut ChaCha20Rng, name: NymName, address: Address) -> Self {
|
||||
let keys = identity::KeyPair::new(rng);
|
||||
let name = NameDetails {
|
||||
name,
|
||||
address,
|
||||
identity_key: keys.public_key().to_base58_string(),
|
||||
};
|
||||
Self {
|
||||
name,
|
||||
keys,
|
||||
rng: rng.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn identity_key(&self) -> &IdentityKey {
|
||||
&self.name.identity_key
|
||||
}
|
||||
|
||||
pub fn details(&self) -> &NameDetails {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn sign(self, payload: SignableNameRegisterMsg) -> SignedTestName {
|
||||
let owner_signature = ed25519_sign_message(payload, self.keys.private_key());
|
||||
SignedTestName {
|
||||
name: self.name,
|
||||
keys: self.keys,
|
||||
owner_signature,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TestName> for NameDetails {
|
||||
fn from(test_name: TestName) -> Self {
|
||||
test_name.name
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SignedTestName {
|
||||
pub name: NameDetails,
|
||||
pub keys: identity::KeyPair,
|
||||
pub owner_signature: MessageSignature,
|
||||
}
|
||||
|
||||
impl SignedTestName {
|
||||
pub fn identity_key(&self) -> &IdentityKey {
|
||||
&self.name.identity_key
|
||||
}
|
||||
|
||||
pub fn details(&self) -> &NameDetails {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignedTestName> for NameDetails {
|
||||
fn from(signed_name: SignedTestName) -> Self {
|
||||
signed_name.name
|
||||
}
|
||||
}
|
||||
+63
-11
@@ -1,13 +1,18 @@
|
||||
use cosmwasm_std::{coins, Addr, Coin, Uint128};
|
||||
use cw_multi_test::{App, AppBuilder, AppResponse, ContractWrapper, Executor};
|
||||
use nym_contracts_common::signing::Nonce;
|
||||
use nym_name_service_common::{
|
||||
msg::{ExecuteMsg, InstantiateMsg, QueryMsg},
|
||||
response::{ConfigResponse, PagedNamesListResponse},
|
||||
Address, NameEntry, NameId, NymName,
|
||||
signing_types::{construct_name_register_sign_payload, SignableNameRegisterMsg},
|
||||
Address, NameDetails, NameId, NymName, RegisteredName,
|
||||
};
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
use crate::test_helpers::helpers::get_app_attribute;
|
||||
use crate::test_helpers::helpers::{get_app_attribute, test_rng};
|
||||
|
||||
use super::test_name::{SignedTestName, TestName};
|
||||
|
||||
const DENOM: &str = "unym";
|
||||
const ADDRESSES: &[&str] = &[
|
||||
@@ -19,6 +24,7 @@ const WEALTHY_ADDRESSES: &[&str] = &["wealthy_owner_1", "wealthy_owner_2"];
|
||||
pub struct TestSetup {
|
||||
app: App,
|
||||
addr: Addr,
|
||||
rng: ChaCha20Rng,
|
||||
}
|
||||
|
||||
impl Default for TestSetup {
|
||||
@@ -44,7 +50,8 @@ impl TestSetup {
|
||||
let code = ContractWrapper::new(crate::execute, crate::instantiate, crate::query);
|
||||
let code_id = app.store_code(Box::new(code));
|
||||
let addr = Self::instantiate(&mut app, code_id);
|
||||
TestSetup { app, addr }
|
||||
let rng = test_rng();
|
||||
TestSetup { app, addr, rng }
|
||||
}
|
||||
|
||||
fn instantiate(app: &mut App, code_id: u64) -> Addr {
|
||||
@@ -76,7 +83,7 @@ impl TestSetup {
|
||||
self.query(&QueryMsg::Config {})
|
||||
}
|
||||
|
||||
pub fn query_id(&self, name_id: NameId) -> NameEntry {
|
||||
pub fn query_id(&self, name_id: NameId) -> RegisteredName {
|
||||
self.query(&QueryMsg::NameId { name_id })
|
||||
}
|
||||
|
||||
@@ -92,16 +99,48 @@ impl TestSetup {
|
||||
self.query(&QueryMsg::All { limit, start_after })
|
||||
}
|
||||
|
||||
pub fn query_signing_nonce(&self, address: String) -> Nonce {
|
||||
self.query(&QueryMsg::SigningNonce { address })
|
||||
}
|
||||
|
||||
pub fn new_name(&mut self, name: &NymName, address: &Address) -> TestName {
|
||||
TestName::new(&mut self.rng, name.clone(), address.clone())
|
||||
}
|
||||
|
||||
pub fn payload_to_sign(
|
||||
&mut self,
|
||||
owner: &Addr,
|
||||
deposit: &Coin,
|
||||
name: &NameDetails,
|
||||
) -> SignableNameRegisterMsg {
|
||||
let nonce = self.query_signing_nonce(owner.to_string());
|
||||
construct_name_register_sign_payload(nonce, owner.clone(), deposit.clone(), name.clone())
|
||||
}
|
||||
|
||||
pub fn new_signed_name(
|
||||
&mut self,
|
||||
name: &NymName,
|
||||
address: &Address,
|
||||
owner: &Addr,
|
||||
deposit: &Coin,
|
||||
) -> SignedTestName {
|
||||
let name = self.new_name(name, address);
|
||||
let payload = self.payload_to_sign(owner, deposit, name.details());
|
||||
name.sign(payload)
|
||||
}
|
||||
|
||||
pub fn try_register(
|
||||
&mut self,
|
||||
name: NymName,
|
||||
address: Address,
|
||||
owner: Addr,
|
||||
name: &SignedTestName,
|
||||
owner: &Addr,
|
||||
) -> anyhow::Result<AppResponse> {
|
||||
self.app.execute_contract(
|
||||
owner,
|
||||
owner.clone(),
|
||||
self.addr.clone(),
|
||||
&ExecuteMsg::Register { name, address },
|
||||
&ExecuteMsg::Register {
|
||||
name: name.name.clone(),
|
||||
owner_signature: name.owner_signature.clone(),
|
||||
},
|
||||
&[Coin {
|
||||
denom: DENOM.to_string(),
|
||||
amount: Uint128::new(100),
|
||||
@@ -109,8 +148,8 @@ impl TestSetup {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn register(&mut self, name: NymName, address: Address, owner: Addr) -> AppResponse {
|
||||
let resp = self.try_register(name, address, owner).unwrap();
|
||||
pub fn register(&mut self, name: &SignedTestName, owner: &Addr) -> AppResponse {
|
||||
let resp = self.try_register(name, owner).unwrap();
|
||||
assert_eq!(
|
||||
get_app_attribute(&resp, "wasm-register", "action"),
|
||||
"register"
|
||||
@@ -118,6 +157,19 @@ impl TestSetup {
|
||||
resp
|
||||
}
|
||||
|
||||
// Convenience function for creating a new signed name, and regsitering it
|
||||
pub fn sign_and_register(
|
||||
&mut self,
|
||||
name: &NymName,
|
||||
address: &Address,
|
||||
owner: &Addr,
|
||||
deposit: &Coin,
|
||||
) -> SignedTestName {
|
||||
let signed_name = self.new_signed_name(name, address, owner, deposit);
|
||||
self.register(&signed_name, owner);
|
||||
signed_name
|
||||
}
|
||||
|
||||
pub fn try_delete(&mut self, name_id: NameId, owner: Addr) -> anyhow::Result<AppResponse> {
|
||||
self.app.execute_contract(
|
||||
owner,
|
||||
@@ -3,16 +3,15 @@
|
||||
#![warn(clippy::expect_used)]
|
||||
#![warn(clippy::unwrap_used)]
|
||||
|
||||
use crate::error::Result;
|
||||
pub use nym_name_service_common::error::{NameServiceError, Result};
|
||||
|
||||
use nym_name_service_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
|
||||
|
||||
#[cfg(not(feature = "library"))]
|
||||
use cosmwasm_std::entry_point;
|
||||
use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response};
|
||||
use error::NameServiceError;
|
||||
|
||||
mod contract;
|
||||
mod error;
|
||||
mod state;
|
||||
|
||||
pub mod constants;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use cosmwasm_std::{Addr, Deps, DepsMut};
|
||||
use cw_controllers::Admin;
|
||||
|
||||
use crate::{constants::ADMIN_KEY, error::Result};
|
||||
use crate::{constants::ADMIN_KEY, Result};
|
||||
|
||||
const ADMIN: Admin = Admin::new(ADMIN_KEY);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use cw_storage_plus::Item;
|
||||
use nym_name_service_common::response::ConfigResponse;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{constants::CONFIG_KEY, error::Result};
|
||||
use crate::{constants::CONFIG_KEY, Result};
|
||||
|
||||
const CONFIG: Item<Config> = Item::new(CONFIG_KEY);
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ pub mod admin;
|
||||
pub mod config;
|
||||
pub mod name_id_counter;
|
||||
pub mod names;
|
||||
pub mod nonce;
|
||||
|
||||
pub(crate) use admin::{assert_admin, set_admin};
|
||||
pub(crate) use config::{deposit_required, load_config, save_config, Config};
|
||||
pub(crate) use name_id_counter::next_name_id_counter;
|
||||
pub(crate) use nonce::{get_signing_nonce, increment_signing_nonce};
|
||||
|
||||
@@ -2,7 +2,7 @@ use cosmwasm_std::Storage;
|
||||
use cw_storage_plus::Item;
|
||||
use nym_name_service_common::NameId;
|
||||
|
||||
use crate::{constants::NAME_ID_COUNTER_KEY, error::Result};
|
||||
use crate::{constants::NAME_ID_COUNTER_KEY, Result};
|
||||
|
||||
const NAME_ID_COUNTER: Item<NameId> = Item::new(NAME_ID_COUNTER_KEY);
|
||||
|
||||
@@ -16,33 +16,56 @@ pub(crate) fn next_name_id_counter(store: &mut dyn Storage) -> Result<NameId> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use nym_name_service_common::NameEntry;
|
||||
use cosmwasm_std::Addr;
|
||||
use nym_name_service_common::RegisteredName;
|
||||
|
||||
use crate::test_helpers::{
|
||||
assert::assert_names,
|
||||
fixture::name_fixture_name,
|
||||
helpers::{delete_name_id, instantiate_test_contract, register_name},
|
||||
helpers::{nyms, test_rng},
|
||||
transactions::{delete_name_id, instantiate_test_contract, register_name},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn get_next_name_id() {
|
||||
let mut deps = instantiate_test_contract();
|
||||
let mut rng = test_rng();
|
||||
|
||||
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("foo")), 1);
|
||||
assert_names(
|
||||
deps.as_ref(),
|
||||
&[NameEntry::new(1, name_fixture_name("foo"))],
|
||||
);
|
||||
|
||||
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("bar")), 2);
|
||||
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("baz")), 3);
|
||||
let (id1, name1) = register_name(deps.as_mut(), &mut rng, "foo", "addr1", "steve");
|
||||
let (id2, name2) = register_name(deps.as_mut(), &mut rng, "bar", "addr2", "steve");
|
||||
let (id3, name3) = register_name(deps.as_mut(), &mut rng, "baz", "addr3", "steve");
|
||||
assert_eq!(id1, 1);
|
||||
assert_eq!(id2, 2);
|
||||
assert_eq!(id3, 3);
|
||||
assert_eq!(name1.name.as_str(), "foo");
|
||||
assert_eq!(name1.address.as_str(), "addr1");
|
||||
assert_eq!(name2.name.as_str(), "bar");
|
||||
assert_eq!(name2.address.as_str(), "addr2");
|
||||
assert_eq!(name3.name.as_str(), "baz");
|
||||
assert_eq!(name3.address.as_str(), "addr3");
|
||||
assert_names(
|
||||
deps.as_ref(),
|
||||
&[
|
||||
NameEntry::new(1, name_fixture_name("foo")),
|
||||
NameEntry::new(2, name_fixture_name("bar")),
|
||||
NameEntry::new(3, name_fixture_name("baz")),
|
||||
RegisteredName {
|
||||
id: 1,
|
||||
name: name1,
|
||||
owner: Addr::unchecked("steve"),
|
||||
block_height: 12345,
|
||||
deposit: nyms(100),
|
||||
},
|
||||
RegisteredName {
|
||||
id: 2,
|
||||
name: name2,
|
||||
owner: Addr::unchecked("steve"),
|
||||
block_height: 12345,
|
||||
deposit: nyms(100),
|
||||
},
|
||||
RegisteredName {
|
||||
id: 3,
|
||||
name: name3,
|
||||
owner: Addr::unchecked("steve"),
|
||||
block_height: 12345,
|
||||
deposit: nyms(100),
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -50,34 +73,28 @@ mod tests {
|
||||
#[test]
|
||||
fn deleted_name_id_is_not_reused() {
|
||||
let mut deps = instantiate_test_contract();
|
||||
let mut rng = test_rng();
|
||||
|
||||
// Register two names
|
||||
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("one")), 1);
|
||||
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("two")), 2);
|
||||
assert_names(
|
||||
deps.as_ref(),
|
||||
&[
|
||||
NameEntry::new(1, name_fixture_name("one")),
|
||||
NameEntry::new(2, name_fixture_name("two")),
|
||||
],
|
||||
);
|
||||
let (_, name1) = register_name(deps.as_mut(), &mut rng, "one", "sdfjkhsdfhr", "steve");
|
||||
register_name(deps.as_mut(), &mut rng, "two", "suereljer", "steve");
|
||||
|
||||
// Delete the last entry
|
||||
delete_name_id(deps.as_mut(), 2, "steve");
|
||||
assert_names(
|
||||
deps.as_ref(),
|
||||
&[NameEntry::new(1, name_fixture_name("one"))],
|
||||
&[RegisteredName {
|
||||
id: 1,
|
||||
name: name1,
|
||||
owner: Addr::unchecked("steve"),
|
||||
block_height: 12345,
|
||||
deposit: nyms(100),
|
||||
}],
|
||||
);
|
||||
|
||||
// Create a third entry. The index should not reuse the previous entry that we just
|
||||
// deleted.
|
||||
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("two")), 3);
|
||||
assert_names(
|
||||
deps.as_ref(),
|
||||
&[
|
||||
NameEntry::new(1, name_fixture_name("one")),
|
||||
NameEntry::new(3, name_fixture_name("two")),
|
||||
],
|
||||
);
|
||||
let (id3, _) = register_name(deps.as_mut(), &mut rng, "three", "ufd", "steve");
|
||||
assert_eq!(id3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::{
|
||||
NAMES_ADDRESS_IDX_NAMESPACE, NAMES_NAME_IDX_NAMESPACE, NAMES_OWNER_IDX_NAMESPACE,
|
||||
NAMES_PK_NAMESPACE, NAME_DEFAULT_RETRIEVAL_LIMIT, NAME_MAX_RETRIEVAL_LIMIT,
|
||||
},
|
||||
error::{NameServiceError, Result},
|
||||
NameServiceError, Result,
|
||||
};
|
||||
|
||||
struct NameIndex<'a> {
|
||||
@@ -28,9 +28,9 @@ impl<'a> IndexList<RegisteredName> for NameIndex<'a> {
|
||||
|
||||
fn names<'a>() -> IndexedMap<'a, NameId, RegisteredName, NameIndex<'a>> {
|
||||
let indexes = NameIndex {
|
||||
name: UniqueIndex::new(|d| d.name.to_string(), NAMES_NAME_IDX_NAMESPACE),
|
||||
name: UniqueIndex::new(|d| d.name.name.to_string(), NAMES_NAME_IDX_NAMESPACE),
|
||||
address: MultiIndex::new(
|
||||
|d| d.address.to_string(),
|
||||
|d| d.name.address.to_string(),
|
||||
NAMES_PK_NAMESPACE,
|
||||
NAMES_ADDRESS_IDX_NAMESPACE,
|
||||
),
|
||||
@@ -43,19 +43,29 @@ fn names<'a>() -> IndexedMap<'a, NameId, RegisteredName, NameIndex<'a>> {
|
||||
IndexedMap::new(NAMES_PK_NAMESPACE, indexes)
|
||||
}
|
||||
|
||||
pub fn save(store: &mut dyn Storage, new_name: &RegisteredName) -> Result<NameId> {
|
||||
let name_id = super::next_name_id_counter(store)?;
|
||||
pub fn save(store: &mut dyn Storage, new_name: &RegisteredName) -> Result<()> {
|
||||
let name_id = new_name.id;
|
||||
names().save(store, name_id, new_name)?;
|
||||
Ok(name_id)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn save_all(state: &mut dyn Storage, names: &[RegisteredName]) -> Result<Vec<NameId>> {
|
||||
let mut ids = vec![];
|
||||
pub fn save_all(state: &mut dyn Storage, names: &[RegisteredName]) -> Result<()> {
|
||||
for name in names {
|
||||
ids.push(save(state, name)?);
|
||||
save(state, name)?;
|
||||
}
|
||||
Ok(ids)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_id(store: &mut dyn Storage, name_id: NameId) -> Result<()> {
|
||||
Ok(names().remove(store, name_id)?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn remove_name(store: &mut dyn Storage, name: NymName) -> Result<NameId> {
|
||||
let registered_name = load_name(store, &name)?;
|
||||
remove_id(store, registered_name.id)?;
|
||||
Ok(registered_name.id)
|
||||
}
|
||||
|
||||
pub fn has_name_id(store: &dyn Storage, name_id: NameId) -> bool {
|
||||
@@ -66,23 +76,6 @@ pub fn has_name(store: &dyn Storage, name: &NymName) -> bool {
|
||||
load_name(store, name).is_ok()
|
||||
}
|
||||
|
||||
// Get the (key, name) entry for a given name
|
||||
pub fn load_name_entry(store: &dyn Storage, name: &NymName) -> Result<(NameId, RegisteredName)> {
|
||||
names()
|
||||
.idx
|
||||
.name
|
||||
.range(store, None, None, Order::Ascending)
|
||||
.find(|entry| {
|
||||
if let Ok(entry) = entry {
|
||||
&entry.1.name == name
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.ok_or(NameServiceError::NameNotFound { name: name.clone() })?
|
||||
.map_err(NameServiceError::from)
|
||||
}
|
||||
|
||||
pub fn load_id(store: &dyn Storage, name_id: NameId) -> Result<RegisteredName> {
|
||||
names().load(store, name_id).map_err(|err| match err {
|
||||
StdError::NotFound { .. } => NameServiceError::NotFound { name_id },
|
||||
@@ -99,45 +92,33 @@ pub fn load_name(store: &dyn Storage, name: &NymName) -> Result<RegisteredName>
|
||||
.ok_or(NameServiceError::NameNotFound { name: name.clone() })
|
||||
}
|
||||
|
||||
pub fn load_address(
|
||||
store: &dyn Storage,
|
||||
address: &Address,
|
||||
) -> Result<Vec<(NameId, RegisteredName)>> {
|
||||
pub fn load_address(store: &dyn Storage, address: &Address) -> Result<Vec<RegisteredName>> {
|
||||
names()
|
||||
.idx
|
||||
.address
|
||||
.prefix(address.to_string())
|
||||
.range(store, None, None, Order::Ascending)
|
||||
.take(MAX_NUMBER_OF_NAMES_FOR_ADDRESS as usize)
|
||||
.map(|res| res.map(|(_, name)| name))
|
||||
.collect::<StdResult<Vec<_>>>()
|
||||
.map_err(NameServiceError::from)
|
||||
}
|
||||
|
||||
pub fn load_owner(store: &dyn Storage, owner: Addr) -> Result<Vec<(NameId, RegisteredName)>> {
|
||||
pub fn load_owner(store: &dyn Storage, owner: Addr) -> Result<Vec<RegisteredName>> {
|
||||
names()
|
||||
.idx
|
||||
.owner
|
||||
.prefix(owner)
|
||||
.range(store, None, None, Order::Ascending)
|
||||
.take(MAX_NUMBER_OF_NAMES_PER_OWNER as usize)
|
||||
.map(|res| res.map(|(_, name)| name))
|
||||
.collect::<StdResult<Vec<_>>>()
|
||||
.map_err(NameServiceError::from)
|
||||
}
|
||||
|
||||
pub fn remove_id(store: &mut dyn Storage, name_id: NameId) -> Result<()> {
|
||||
Ok(names().remove(store, name_id)?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn remove_name(store: &mut dyn Storage, name: NymName) -> Result<NameId> {
|
||||
let name_info = load_name_entry(store, &name)?;
|
||||
remove_id(store, name_info.0)?;
|
||||
Ok(name_info.0)
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct PagedLoad {
|
||||
pub names: Vec<(NameId, RegisteredName)>,
|
||||
pub names: Vec<RegisteredName>,
|
||||
pub limit: usize,
|
||||
pub start_next_after: Option<NameId>,
|
||||
}
|
||||
@@ -156,9 +137,10 @@ pub fn load_all_paged(
|
||||
let names = names()
|
||||
.range(store, start, None, Order::Ascending)
|
||||
.take(limit)
|
||||
.map(|res| res.map(|(_, name)| name))
|
||||
.collect::<StdResult<Vec<_>>>()?;
|
||||
|
||||
let start_next_after = names.last().map(|name| name.0);
|
||||
let start_next_after = names.last().map(|name| name.id);
|
||||
|
||||
Ok(PagedLoad {
|
||||
names,
|
||||
@@ -169,8 +151,6 @@ pub fn load_all_paged(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::iter::zip;
|
||||
|
||||
use cosmwasm_std::{
|
||||
testing::{MockApi, MockQuerier},
|
||||
MemoryStorage, OwnedDeps,
|
||||
@@ -178,11 +158,11 @@ mod tests {
|
||||
use rstest::rstest;
|
||||
|
||||
use crate::{
|
||||
error::NameServiceError,
|
||||
test_helpers::{
|
||||
fixture::{name_fixture, name_fixture_full},
|
||||
helpers::instantiate_test_contract,
|
||||
transactions::instantiate_test_contract,
|
||||
},
|
||||
NameServiceError,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
@@ -197,64 +177,55 @@ mod tests {
|
||||
#[rstest::fixture]
|
||||
fn uniq_names() -> Vec<RegisteredName> {
|
||||
vec![
|
||||
name_fixture_full("one", "address_one", "owner_one"),
|
||||
name_fixture_full("two", "address_two", "owner_two"),
|
||||
name_fixture_full("three", "address_three", "owner_three"),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(2, "two", "address_two", "owner_two"),
|
||||
name_fixture_full(3, "three", "address_three", "owner_three"),
|
||||
]
|
||||
}
|
||||
|
||||
#[rstest::fixture]
|
||||
fn overlapping_addresses() -> Vec<RegisteredName> {
|
||||
vec![
|
||||
name_fixture_full("one", "address_one", "owner_one"),
|
||||
name_fixture_full("two", "address_two", "owner_two"),
|
||||
name_fixture_full("three", "address_two", "owner_three"),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(2, "two", "address_two", "owner_two"),
|
||||
name_fixture_full(3, "three", "address_two", "owner_three"),
|
||||
]
|
||||
}
|
||||
|
||||
#[rstest::fixture]
|
||||
fn overlapping_owners() -> Vec<RegisteredName> {
|
||||
vec![
|
||||
name_fixture_full("one", "address_one", "owner_one"),
|
||||
name_fixture_full("two", "address_two", "owner_two"),
|
||||
name_fixture_full("three", "address_three", "owner_two"),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(2, "two", "address_two", "owner_two"),
|
||||
name_fixture_full(3, "three", "address_three", "owner_two"),
|
||||
]
|
||||
}
|
||||
|
||||
fn assert_not_registered(store: &dyn Storage, names: Vec<RegisteredName>, ids: Vec<NameId>) {
|
||||
let names: Vec<(NameId, RegisteredName)> = zip(ids, names).collect();
|
||||
fn assert_not_registered(store: &dyn Storage, names: Vec<RegisteredName>) {
|
||||
let loaded = load_all_paged(store, None, None).unwrap();
|
||||
for (id, name) in &names {
|
||||
assert!(!has_name_id(store, *id));
|
||||
assert!(!has_name(store, &name.name));
|
||||
assert!(!loaded.names.iter().any(|(i, _)| i == id));
|
||||
assert!(!loaded.names.iter().any(|(_, n)| n == name));
|
||||
for name in &names {
|
||||
assert!(!has_name_id(store, name.id));
|
||||
assert!(!has_name(store, name.entry()));
|
||||
assert!(!loaded.names.iter().any(|l_name| l_name.id == name.id));
|
||||
assert!(!loaded.names.iter().any(|l_name| l_name == name));
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_registered(store: &dyn Storage, names: Vec<RegisteredName>, ids: Vec<NameId>) {
|
||||
assert!(names.len() == ids.len());
|
||||
let names: Vec<(NameId, RegisteredName)> = zip(ids, names).collect();
|
||||
fn assert_registered(store: &dyn Storage, names: Vec<RegisteredName>) {
|
||||
let loaded = load_all_paged(store, None, None).unwrap();
|
||||
for (id, name) in &names {
|
||||
assert!(has_name_id(store, *id));
|
||||
assert!(has_name(store, &name.name));
|
||||
assert!(loaded.names.iter().filter(|(i, _)| i == id).count() == 1);
|
||||
assert!(loaded.names.iter().filter(|(_, n)| n == name).count() == 1);
|
||||
for name in &names {
|
||||
assert!(has_name_id(store, name.id));
|
||||
assert!(has_name(store, name.entry()));
|
||||
assert!(loaded.names.iter().filter(|n| n == &name).count() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_only_these_registered(
|
||||
store: &dyn Storage,
|
||||
names: Vec<RegisteredName>,
|
||||
ids: Vec<NameId>,
|
||||
) {
|
||||
let last_id = *ids.last().unwrap();
|
||||
let names: Vec<(NameId, RegisteredName)> = zip(ids, names).collect();
|
||||
for (id, name) in &names {
|
||||
assert!(has_name_id(store, *id));
|
||||
assert!(has_name(store, &name.name));
|
||||
fn assert_only_these_registered(store: &dyn Storage, names: Vec<RegisteredName>) {
|
||||
for name in &names {
|
||||
assert!(has_name_id(store, name.id));
|
||||
assert!(has_name(store, name.entry()));
|
||||
}
|
||||
let last_id = names.last().unwrap().id;
|
||||
assert_eq!(
|
||||
load_all_paged(store, None, None).unwrap(),
|
||||
PagedLoad {
|
||||
@@ -267,102 +238,107 @@ mod tests {
|
||||
|
||||
#[rstest]
|
||||
fn single_basic_save_works(mut deps: TestDeps) {
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn save_same_name_twice_fails(mut deps: TestDeps) {
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
|
||||
assert!(matches!(
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap_err(),
|
||||
save(deps.as_mut().storage, &name_fixture(2)).unwrap_err(),
|
||||
NameServiceError::Std(StdError::GenericErr { .. })
|
||||
));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn remove_id_works(mut deps: TestDeps) {
|
||||
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
|
||||
assert!(has_name_id(&deps.storage, 1));
|
||||
assert!(has_name(&deps.storage, name_fixture(1).entry()));
|
||||
remove_id(deps.as_mut().storage, 1).unwrap();
|
||||
assert!(!has_name_id(&deps.storage, 1));
|
||||
assert!(!has_name(&deps.storage, name_fixture(1).entry()));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn remove_name_works(mut deps: TestDeps) {
|
||||
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
|
||||
assert!(has_name_id(&deps.storage, 1));
|
||||
assert!(has_name(&deps.storage, name_fixture(1).entry()));
|
||||
remove_name(deps.as_mut().storage, name_fixture(1).name.name).unwrap();
|
||||
assert!(!has_name_id(&deps.storage, 1));
|
||||
assert!(!has_name(&deps.storage, name_fixture(1).entry()));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn has_name_works(mut deps: TestDeps) {
|
||||
assert!(!has_name(&deps.storage, &name_fixture().name));
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
assert!(has_name(&deps.storage, &name_fixture().name));
|
||||
assert!(!has_name(&deps.storage, name_fixture(1).entry()));
|
||||
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
|
||||
assert!(has_name(&deps.storage, name_fixture(1).entry()));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn has_name_id_works(mut deps: TestDeps) {
|
||||
assert!(!has_name_id(&deps.storage, 1));
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
|
||||
assert!(has_name_id(&deps.storage, 1));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn has_name_id_with_incorrect_id_fails(mut deps: TestDeps) {
|
||||
assert!(!has_name_id(&deps.storage, 2));
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
|
||||
assert!(!has_name_id(&deps.storage, 2));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn load_name_entry_works(mut deps: TestDeps) {
|
||||
assert_eq!(
|
||||
load_name_entry(deps.as_ref().storage, &name_fixture().name).unwrap_err(),
|
||||
NameServiceError::NameNotFound {
|
||||
name: name_fixture().name
|
||||
}
|
||||
);
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
assert_eq!(
|
||||
load_name_entry(deps.as_ref().storage, &name_fixture().name).unwrap(),
|
||||
(1, name_fixture())
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn load_id_works(mut deps: TestDeps) {
|
||||
assert_eq!(
|
||||
load_id(deps.as_ref().storage, 1).unwrap_err(),
|
||||
NameServiceError::NotFound { name_id: 1 }
|
||||
);
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
assert_eq!(load_id(deps.as_ref().storage, 1).unwrap(), name_fixture(),);
|
||||
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
|
||||
assert_eq!(load_id(deps.as_ref().storage, 1).unwrap(), name_fixture(1),);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn load_name_works(mut deps: TestDeps) {
|
||||
assert_eq!(
|
||||
load_name(deps.as_ref().storage, &name_fixture().name).unwrap_err(),
|
||||
load_name(deps.as_ref().storage, name_fixture(1).entry()).unwrap_err(),
|
||||
NameServiceError::NameNotFound {
|
||||
name: name_fixture().name
|
||||
name: name_fixture(1).name.name,
|
||||
}
|
||||
);
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
|
||||
assert_eq!(
|
||||
load_name(deps.as_ref().storage, &name_fixture().name).unwrap(),
|
||||
name_fixture(),
|
||||
load_name(deps.as_ref().storage, name_fixture(1).entry()).unwrap(),
|
||||
name_fixture(1),
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn load_address_works(mut deps: TestDeps) {
|
||||
assert_eq!(
|
||||
load_address(deps.as_ref().storage, &name_fixture().address).unwrap(),
|
||||
load_address(deps.as_ref().storage, &name_fixture(1).name.address).unwrap(),
|
||||
vec![],
|
||||
);
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
|
||||
assert_eq!(
|
||||
load_address(deps.as_ref().storage, &name_fixture().address).unwrap(),
|
||||
vec![(1, name_fixture())],
|
||||
load_address(deps.as_ref().storage, &name_fixture(1).name.address).unwrap(),
|
||||
vec![name_fixture(1)],
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn load_owner_works(mut deps: TestDeps) {
|
||||
assert_eq!(
|
||||
load_owner(deps.as_ref().storage, name_fixture().owner).unwrap(),
|
||||
load_owner(deps.as_ref().storage, name_fixture(1).owner).unwrap(),
|
||||
vec![],
|
||||
);
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
|
||||
assert_eq!(
|
||||
load_owner(deps.as_ref().storage, name_fixture().owner).unwrap(),
|
||||
vec![(1, name_fixture())],
|
||||
load_owner(deps.as_ref().storage, name_fixture(1).owner).unwrap(),
|
||||
vec![name_fixture(1)],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -380,60 +356,19 @@ mod tests {
|
||||
assert_eq!(
|
||||
load_all_paged(&deps.storage, None, None).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![(1, uniq_names[0].clone())],
|
||||
names: vec![uniq_names[0].clone()],
|
||||
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(1),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn remove_id_works(mut deps: TestDeps) {
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
assert!(has_name_id(&deps.storage, 1));
|
||||
assert!(has_name(&deps.storage, &name_fixture().name));
|
||||
remove_id(deps.as_mut().storage, 1).unwrap();
|
||||
assert!(!has_name_id(&deps.storage, 1));
|
||||
assert!(!has_name(&deps.storage, &name_fixture().name));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn remove_name_works(mut deps: TestDeps) {
|
||||
save(deps.as_mut().storage, &name_fixture()).unwrap();
|
||||
assert!(has_name_id(&deps.storage, 1));
|
||||
assert!(has_name(&deps.storage, &name_fixture().name));
|
||||
remove_name(deps.as_mut().storage, name_fixture().name).unwrap();
|
||||
assert!(!has_name_id(&deps.storage, 1));
|
||||
assert!(!has_name(&deps.storage, &name_fixture().name));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn save_set_of_unique_names_works(mut deps: TestDeps, uniq_names: Vec<RegisteredName>) {
|
||||
let num = uniq_names.len() as NameId;
|
||||
let ids = (1..=num).collect::<Vec<NameId>>();
|
||||
assert_not_registered(&deps.storage, uniq_names.clone(), ids.clone());
|
||||
let saved_ids = save_all(deps.as_mut().storage, &uniq_names).unwrap();
|
||||
assert_eq!(saved_ids, ids);
|
||||
assert_registered(&deps.storage, uniq_names.clone(), ids.clone());
|
||||
assert_only_these_registered(&deps.storage, uniq_names, ids);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn save_set_of_unique_names_generates_ids(mut deps: TestDeps, uniq_names: Vec<RegisteredName>) {
|
||||
let num = uniq_names.len() as NameId;
|
||||
let ids = save_all(deps.as_mut().storage, &uniq_names).unwrap();
|
||||
assert_eq!(ids, (1..=num).collect::<Vec<NameId>>());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn load_name_entry_for_unique_set_works(mut deps: TestDeps, uniq_names: Vec<RegisteredName>) {
|
||||
assert_not_registered(&deps.storage, uniq_names.clone());
|
||||
save_all(deps.as_mut().storage, &uniq_names).unwrap();
|
||||
for (id, name) in uniq_names.iter().enumerate() {
|
||||
assert_eq!(
|
||||
load_name_entry(deps.as_ref().storage, &name.name).unwrap(),
|
||||
(id as NameId + 1, name.clone()),
|
||||
);
|
||||
}
|
||||
assert_registered(&deps.storage, uniq_names.clone());
|
||||
assert_only_these_registered(&deps.storage, uniq_names);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
@@ -441,7 +376,7 @@ mod tests {
|
||||
save_all(deps.as_mut().storage, &uniq_names).unwrap();
|
||||
for name in uniq_names {
|
||||
assert_eq!(
|
||||
load_name(deps.as_ref().storage, &name.name).unwrap(),
|
||||
load_name(deps.as_ref().storage, name.entry()).unwrap(),
|
||||
name.clone(),
|
||||
);
|
||||
}
|
||||
@@ -452,17 +387,14 @@ mod tests {
|
||||
mut deps: TestDeps,
|
||||
uniq_names: Vec<RegisteredName>,
|
||||
) {
|
||||
let ids = save_all(deps.as_mut().storage, &uniq_names).unwrap();
|
||||
remove_id(deps.as_mut().storage, ids[1]).unwrap();
|
||||
save_all(deps.as_mut().storage, &uniq_names).unwrap();
|
||||
remove_id(deps.as_mut().storage, 2).unwrap();
|
||||
assert_eq!(
|
||||
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![
|
||||
(1, name_fixture_full("one", "address_one", "owner_one")),
|
||||
(
|
||||
3,
|
||||
name_fixture_full("three", "address_three", "owner_three")
|
||||
),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(3, "three", "address_three", "owner_three"),
|
||||
],
|
||||
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(3),
|
||||
@@ -476,16 +408,13 @@ mod tests {
|
||||
uniq_names: Vec<RegisteredName>,
|
||||
) {
|
||||
save_all(deps.as_mut().storage, &uniq_names).unwrap();
|
||||
remove_name(deps.as_mut().storage, uniq_names[1].name.clone()).unwrap();
|
||||
remove_name(deps.as_mut().storage, uniq_names[1].entry().clone()).unwrap();
|
||||
assert_eq!(
|
||||
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![
|
||||
(1, name_fixture_full("one", "address_one", "owner_one")),
|
||||
(
|
||||
3,
|
||||
name_fixture_full("three", "address_three", "owner_three")
|
||||
),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(3, "three", "address_three", "owner_three"),
|
||||
],
|
||||
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(3),
|
||||
@@ -498,9 +427,9 @@ mod tests {
|
||||
mut deps: TestDeps,
|
||||
overlapping_addresses: Vec<RegisteredName>,
|
||||
) {
|
||||
let ids = save_all(deps.as_mut().storage, &overlapping_addresses).unwrap();
|
||||
assert_registered(&deps.storage, overlapping_addresses.clone(), ids.clone());
|
||||
assert_only_these_registered(&deps.storage, overlapping_addresses, ids);
|
||||
save_all(deps.as_mut().storage, &overlapping_addresses).unwrap();
|
||||
assert_registered(&deps.storage, overlapping_addresses.clone());
|
||||
assert_only_these_registered(&deps.storage, overlapping_addresses);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
@@ -513,9 +442,9 @@ mod tests {
|
||||
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![
|
||||
(1, name_fixture_full("one", "address_one", "owner_one")),
|
||||
(2, name_fixture_full("two", "address_two", "owner_two")),
|
||||
(3, name_fixture_full("three", "address_two", "owner_three")),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(2, "two", "address_two", "owner_two"),
|
||||
name_fixture_full(3, "three", "address_two", "owner_three"),
|
||||
],
|
||||
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(3),
|
||||
@@ -524,8 +453,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
load_address(deps.as_ref().storage, &Address::new("address_two")).unwrap(),
|
||||
vec![
|
||||
(2, name_fixture_full("two", "address_two", "owner_two")),
|
||||
(3, name_fixture_full("three", "address_two", "owner_three")),
|
||||
name_fixture_full(2, "two", "address_two", "owner_two"),
|
||||
name_fixture_full(3, "three", "address_two", "owner_three"),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -535,14 +464,14 @@ mod tests {
|
||||
mut deps: TestDeps,
|
||||
overlapping_addresses: Vec<RegisteredName>,
|
||||
) {
|
||||
let ids = save_all(deps.as_mut().storage, &overlapping_addresses).unwrap();
|
||||
remove_id(deps.as_mut().storage, ids[1]).unwrap();
|
||||
save_all(deps.as_mut().storage, &overlapping_addresses).unwrap();
|
||||
remove_id(deps.as_mut().storage, 2).unwrap();
|
||||
assert_eq!(
|
||||
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![
|
||||
(1, name_fixture_full("one", "address_one", "owner_one")),
|
||||
(3, name_fixture_full("three", "address_two", "owner_three")),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(3, "three", "address_two", "owner_three"),
|
||||
],
|
||||
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(3),
|
||||
@@ -556,13 +485,17 @@ mod tests {
|
||||
overlapping_addresses: Vec<RegisteredName>,
|
||||
) {
|
||||
save_all(deps.as_mut().storage, &overlapping_addresses).unwrap();
|
||||
remove_name(deps.as_mut().storage, overlapping_addresses[1].name.clone()).unwrap();
|
||||
remove_name(
|
||||
deps.as_mut().storage,
|
||||
overlapping_addresses[1].name.name.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![
|
||||
(1, name_fixture_full("one", "address_one", "owner_one")),
|
||||
(3, name_fixture_full("three", "address_two", "owner_three")),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(3, "three", "address_two", "owner_three"),
|
||||
],
|
||||
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(3),
|
||||
@@ -575,9 +508,9 @@ mod tests {
|
||||
mut deps: TestDeps,
|
||||
overlapping_owners: Vec<RegisteredName>,
|
||||
) {
|
||||
let ids = save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
|
||||
assert_registered(&deps.storage, overlapping_owners.clone(), ids.clone());
|
||||
assert_only_these_registered(&deps.storage, overlapping_owners, ids);
|
||||
save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
|
||||
assert_registered(&deps.storage, overlapping_owners.clone());
|
||||
assert_only_these_registered(&deps.storage, overlapping_owners);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
@@ -590,9 +523,9 @@ mod tests {
|
||||
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![
|
||||
(1, name_fixture_full("one", "address_one", "owner_one")),
|
||||
(2, name_fixture_full("two", "address_two", "owner_two")),
|
||||
(3, name_fixture_full("three", "address_three", "owner_two")),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(2, "two", "address_two", "owner_two"),
|
||||
name_fixture_full(3, "three", "address_three", "owner_two"),
|
||||
],
|
||||
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(3),
|
||||
@@ -601,8 +534,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
load_owner(deps.as_ref().storage, Addr::unchecked("owner_two")).unwrap(),
|
||||
vec![
|
||||
(2, name_fixture_full("two", "address_two", "owner_two")),
|
||||
(3, name_fixture_full("three", "address_three", "owner_two")),
|
||||
name_fixture_full(2, "two", "address_two", "owner_two"),
|
||||
name_fixture_full(3, "three", "address_three", "owner_two"),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -612,16 +545,16 @@ mod tests {
|
||||
mut deps: TestDeps,
|
||||
overlapping_owners: Vec<RegisteredName>,
|
||||
) {
|
||||
let ids = save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
|
||||
assert_registered(&deps.storage, overlapping_owners.clone(), ids.clone());
|
||||
assert_only_these_registered(&deps.storage, overlapping_owners, ids);
|
||||
save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
|
||||
assert_registered(&deps.storage, overlapping_owners.clone());
|
||||
assert_only_these_registered(&deps.storage, overlapping_owners);
|
||||
remove_id(deps.as_mut().storage, 2).unwrap();
|
||||
assert_eq!(
|
||||
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![
|
||||
(1, name_fixture_full("one", "address_one", "owner_one")),
|
||||
(3, name_fixture_full("three", "address_three", "owner_two")),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(3, "three", "address_three", "owner_two"),
|
||||
],
|
||||
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(3),
|
||||
@@ -634,16 +567,16 @@ mod tests {
|
||||
mut deps: TestDeps,
|
||||
overlapping_owners: Vec<RegisteredName>,
|
||||
) {
|
||||
let ids = save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
|
||||
assert_registered(&deps.storage, overlapping_owners.clone(), ids.clone());
|
||||
assert_only_these_registered(&deps.storage, overlapping_owners.clone(), ids);
|
||||
remove_name(deps.as_mut().storage, overlapping_owners[1].name.clone()).unwrap();
|
||||
save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
|
||||
assert_registered(&deps.storage, overlapping_owners.clone());
|
||||
assert_only_these_registered(&deps.storage, overlapping_owners.clone());
|
||||
remove_name(deps.as_mut().storage, overlapping_owners[1].entry().clone()).unwrap();
|
||||
assert_eq!(
|
||||
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![
|
||||
(1, name_fixture_full("one", "address_one", "owner_one")),
|
||||
(3, name_fixture_full("three", "address_three", "owner_two")),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(3, "three", "address_three", "owner_two"),
|
||||
],
|
||||
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
|
||||
start_next_after: Some(3),
|
||||
@@ -658,8 +591,8 @@ mod tests {
|
||||
load_all_paged(&deps.storage, Some(2), None).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![
|
||||
(1, name_fixture_full("one", "address_one", "owner_one")),
|
||||
(2, name_fixture_full("two", "address_two", "owner_two")),
|
||||
name_fixture_full(1, "one", "address_one", "owner_one"),
|
||||
name_fixture_full(2, "two", "address_two", "owner_two"),
|
||||
],
|
||||
limit: 2,
|
||||
start_next_after: Some(2),
|
||||
@@ -668,10 +601,12 @@ mod tests {
|
||||
assert_eq!(
|
||||
load_all_paged(&deps.storage, Some(1), Some(2)).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![(
|
||||
names: vec![name_fixture_full(
|
||||
3,
|
||||
name_fixture_full("three", "address_three", "owner_three")
|
||||
),],
|
||||
"three",
|
||||
"address_three",
|
||||
"owner_three"
|
||||
)],
|
||||
limit: 1,
|
||||
start_next_after: Some(3),
|
||||
}
|
||||
@@ -679,10 +614,12 @@ mod tests {
|
||||
assert_eq!(
|
||||
load_all_paged(&deps.storage, Some(2), Some(2)).unwrap(),
|
||||
PagedLoad {
|
||||
names: vec![(
|
||||
names: vec![name_fixture_full(
|
||||
3,
|
||||
name_fixture_full("three", "address_three", "owner_three")
|
||||
),],
|
||||
"three",
|
||||
"address_three",
|
||||
"owner_three"
|
||||
)],
|
||||
limit: 2,
|
||||
start_next_after: Some(3),
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{constants::SIGNING_NONCES_NAMESPACE, Result};
|
||||
|
||||
use cosmwasm_std::{Addr, Storage};
|
||||
use cw_storage_plus::Map;
|
||||
use nym_contracts_common::signing::Nonce;
|
||||
|
||||
pub const NONCES: Map<'_, Addr, Nonce> = Map::new(SIGNING_NONCES_NAMESPACE);
|
||||
|
||||
pub fn get_signing_nonce(storage: &dyn Storage, address: Addr) -> Result<Nonce> {
|
||||
let nonce = NONCES.may_load(storage, address)?.unwrap_or(0);
|
||||
Ok(nonce)
|
||||
}
|
||||
|
||||
fn update_signing_nonce(storage: &mut dyn Storage, address: Addr, value: Nonce) -> Result<()> {
|
||||
NONCES
|
||||
.save(storage, address, &value)
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
|
||||
pub fn increment_signing_nonce(storage: &mut dyn Storage, address: Addr) -> Result<()> {
|
||||
// get the current nonce
|
||||
let nonce = get_signing_nonce(storage, address.clone())?;
|
||||
|
||||
// increment it for the next use
|
||||
update_signing_nonce(storage, address, nonce + 1)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test_helpers::transactions::instantiate_test_contract;
|
||||
use cosmwasm_std::{
|
||||
testing::{MockApi, MockQuerier},
|
||||
MemoryStorage, OwnedDeps,
|
||||
};
|
||||
use rstest::rstest;
|
||||
|
||||
type TestDeps = OwnedDeps<MemoryStorage, MockApi, MockQuerier>;
|
||||
|
||||
#[rstest::fixture]
|
||||
fn deps() -> TestDeps {
|
||||
instantiate_test_contract()
|
||||
}
|
||||
|
||||
fn addr(s: &str) -> Addr {
|
||||
Addr::unchecked(s)
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn getting_signing_nonce_doesnt_increment_it(deps: TestDeps) {
|
||||
assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 0);
|
||||
assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 0);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn increment_works(mut deps: TestDeps) {
|
||||
assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 0);
|
||||
increment_signing_nonce(&mut deps.storage, addr("gunnar")).unwrap();
|
||||
assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 1);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn incrementing_is_independent(mut deps: TestDeps) {
|
||||
increment_signing_nonce(&mut deps.storage, addr("gunnar")).unwrap();
|
||||
assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 1);
|
||||
assert_eq!(get_signing_nonce(&deps.storage, addr("bjorn")).unwrap(), 0);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
use cosmwasm_std::{from_binary, testing::mock_env, Addr, Coin, Deps};
|
||||
use nym_contracts_common::signing::Nonce;
|
||||
use nym_name_service_common::{
|
||||
msg::QueryMsg,
|
||||
response::{ConfigResponse, PagedNamesListResponse},
|
||||
NameEntry, NameId,
|
||||
NameId, RegisteredName,
|
||||
};
|
||||
|
||||
use crate::{constants::NAME_DEFAULT_RETRIEVAL_LIMIT, error::NameServiceError};
|
||||
use crate::{constants::NAME_DEFAULT_RETRIEVAL_LIMIT, NameServiceError};
|
||||
|
||||
pub fn assert_config(deps: Deps, admin: &Addr, deposit_required: Coin) {
|
||||
crate::state::assert_admin(deps, admin).unwrap();
|
||||
@@ -14,10 +15,10 @@ pub fn assert_config(deps: Deps, admin: &Addr, deposit_required: Coin) {
|
||||
assert_eq!(config, ConfigResponse { deposit_required });
|
||||
}
|
||||
|
||||
pub fn assert_names(deps: Deps, expected_names: &[NameEntry]) {
|
||||
pub fn assert_names(deps: Deps, expected_names: &[RegisteredName]) {
|
||||
let res = crate::contract::query(deps, mock_env(), QueryMsg::all()).unwrap();
|
||||
let names: PagedNamesListResponse = from_binary(&res).unwrap();
|
||||
let start_next_after = expected_names.iter().last().map(|s| s.name_id);
|
||||
let start_next_after = expected_names.iter().last().map(|s| s.id);
|
||||
assert_eq!(
|
||||
names,
|
||||
PagedNamesListResponse {
|
||||
@@ -28,16 +29,16 @@ pub fn assert_names(deps: Deps, expected_names: &[NameEntry]) {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn assert_name(deps: Deps, expected_name: &NameEntry) {
|
||||
pub fn assert_name(deps: Deps, expected_name: &RegisteredName) {
|
||||
let res = crate::contract::query(
|
||||
deps,
|
||||
mock_env(),
|
||||
QueryMsg::NameId {
|
||||
name_id: expected_name.name_id,
|
||||
name_id: expected_name.id,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let names: NameEntry = from_binary(&res).unwrap();
|
||||
let names: RegisteredName = from_binary(&res).unwrap();
|
||||
assert_eq!(&names, expected_name);
|
||||
}
|
||||
|
||||
@@ -63,3 +64,16 @@ pub fn assert_not_found(deps: Deps, expected_id: NameId) {
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
pub fn assert_current_nonce(deps: Deps, address: &Addr, expected_nonce: Nonce) {
|
||||
let res = crate::contract::query(
|
||||
deps,
|
||||
mock_env(),
|
||||
QueryMsg::SigningNonce {
|
||||
address: address.to_string(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let nonce: Nonce = from_binary(&res).unwrap();
|
||||
assert_eq!(nonce, expected_nonce);
|
||||
}
|
||||
|
||||
@@ -1,29 +1,103 @@
|
||||
use cosmwasm_std::Addr;
|
||||
use nym_name_service_common::{Address, NameEntry, NameId, NymName, RegisteredName};
|
||||
use cosmwasm_std::{Addr, Coin, DepsMut};
|
||||
use nym_contracts_common::{signing::MessageSignature, IdentityKeyRef};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_name_service_common::{Address, NameDetails, NameId, NymName, RegisteredName};
|
||||
use rand_chacha::rand_core::{CryptoRng, RngCore};
|
||||
|
||||
use super::helpers::nyms;
|
||||
use super::{
|
||||
helpers::nyms,
|
||||
signing::{ed25519_sign_message, name_register_sign_payload},
|
||||
};
|
||||
|
||||
pub fn name_fixture_full(name: &str, nym_address: &str, owner: &str) -> RegisteredName {
|
||||
pub fn new_name(
|
||||
name_id: NameId,
|
||||
name: &NymName,
|
||||
address: &Address,
|
||||
owner: &Addr,
|
||||
identity_key: IdentityKeyRef,
|
||||
) -> RegisteredName {
|
||||
RegisteredName {
|
||||
name: NymName::new(name).unwrap(),
|
||||
address: Address::new(nym_address),
|
||||
owner: Addr::unchecked(owner),
|
||||
id: name_id,
|
||||
name: NameDetails {
|
||||
name: name.clone(),
|
||||
address: address.clone(),
|
||||
identity_key: identity_key.to_string(),
|
||||
},
|
||||
owner: owner.clone(),
|
||||
block_height: 12345,
|
||||
deposit: nyms(100),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name_fixture() -> RegisteredName {
|
||||
name_fixture_full("my-service", "client_id.client_key@gateway_id", "steve")
|
||||
pub fn name_fixture(id: NameId) -> RegisteredName {
|
||||
new_name(
|
||||
id,
|
||||
&NymName::new("my-service").unwrap(),
|
||||
&Address::new("client_id.client_key@gateway_id"),
|
||||
&Addr::unchecked("steve"),
|
||||
"identity",
|
||||
)
|
||||
}
|
||||
|
||||
pub fn name_fixture_name(name: &str) -> RegisteredName {
|
||||
name_fixture_full(name, "client_id.client_key@gateway_id", "steve")
|
||||
#[allow(unused)]
|
||||
pub fn name_fixture_with_name(id: NameId, name: &str, address: &str) -> RegisteredName {
|
||||
new_name(
|
||||
id,
|
||||
&NymName::new(name).unwrap(),
|
||||
&Address::new(address),
|
||||
&Addr::unchecked("steve"),
|
||||
"identity",
|
||||
)
|
||||
}
|
||||
|
||||
pub fn name_entry(name_id: NameId, name: NymName, address: Address, owner: Addr) -> NameEntry {
|
||||
NameEntry {
|
||||
name_id,
|
||||
name: name_fixture_full(name.as_str(), address.as_str(), owner.as_str()),
|
||||
}
|
||||
pub fn name_fixture_full(id: NameId, name: &str, address: &str, owner: &str) -> RegisteredName {
|
||||
new_name(
|
||||
id,
|
||||
&NymName::new(name).unwrap(),
|
||||
&Address::new(address),
|
||||
&Addr::unchecked(owner),
|
||||
"identity",
|
||||
)
|
||||
}
|
||||
|
||||
// Create a new name, using a correctly generted identity key
|
||||
pub fn new_name_details<R>(
|
||||
rng: &mut R,
|
||||
name: &str,
|
||||
nym_address: &str,
|
||||
) -> (NameDetails, identity::KeyPair)
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let keypair = identity::KeyPair::new(rng);
|
||||
(
|
||||
NameDetails {
|
||||
name: NymName::new(name).unwrap(),
|
||||
address: Address::new(nym_address),
|
||||
identity_key: keypair.public_key().to_base58_string(),
|
||||
},
|
||||
keypair,
|
||||
)
|
||||
}
|
||||
|
||||
// Create a new service, with a correctly generated identity key, and sign it
|
||||
pub fn new_name_details_with_sign<R>(
|
||||
deps: DepsMut<'_>,
|
||||
rng: &mut R,
|
||||
name: &str,
|
||||
nym_address: &str,
|
||||
owner: &str,
|
||||
deposit: Coin,
|
||||
) -> (NameDetails, MessageSignature)
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
// Service
|
||||
let (name, keypair) = new_name_details(rng, name, nym_address);
|
||||
|
||||
// Sign
|
||||
let sign_msg = name_register_sign_payload(deps.as_ref(), owner, name.clone(), deposit);
|
||||
let owner_signature = ed25519_sign_message(sign_msg, keypair.private_key());
|
||||
|
||||
(name, owner_signature)
|
||||
}
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
use cosmwasm_std::{
|
||||
coin, coins,
|
||||
testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier},
|
||||
Coin, DepsMut, Event, MemoryStorage, OwnedDeps, Response,
|
||||
};
|
||||
use cosmwasm_std::{Coin, Event, Response};
|
||||
use cw_multi_test::AppResponse;
|
||||
use nym_name_service_common::{
|
||||
events::{NameEventType, NAME_ID},
|
||||
msg::{ExecuteMsg, InstantiateMsg},
|
||||
NameId, NymName, RegisteredName,
|
||||
};
|
||||
use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng};
|
||||
|
||||
pub fn nyms(amount: u64) -> Coin {
|
||||
Coin::new(amount.into(), "unym")
|
||||
}
|
||||
|
||||
pub fn test_rng() -> ChaCha20Rng {
|
||||
let dummy_seed = [42u8; 32];
|
||||
ChaCha20Rng::from_seed(dummy_seed)
|
||||
}
|
||||
|
||||
pub fn get_event_types(response: &Response, event_type: &str) -> Vec<Event> {
|
||||
response
|
||||
.events
|
||||
@@ -55,53 +52,3 @@ pub fn get_app_attribute(response: &AppResponse, event_type: &str, key: &str) ->
|
||||
.value
|
||||
.clone()
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn get_app_attributes(response: &AppResponse, event_type: &str, key: &str) -> Vec<String> {
|
||||
get_app_event_types(response, event_type)
|
||||
.iter()
|
||||
.map(|ev| {
|
||||
ev.attributes
|
||||
.iter()
|
||||
.find(|attr| attr.key == key)
|
||||
.unwrap()
|
||||
.value
|
||||
.clone()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn instantiate_test_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier> {
|
||||
let mut deps = mock_dependencies();
|
||||
let msg = InstantiateMsg {
|
||||
deposit_required: coin(100, "unym"),
|
||||
};
|
||||
let env = mock_env();
|
||||
let info = mock_info("creator", &[]);
|
||||
let res = crate::instantiate(deps.as_mut(), env, info, msg).unwrap();
|
||||
assert_eq!(res.messages.len(), 0);
|
||||
deps
|
||||
}
|
||||
|
||||
pub fn register_name(deps: DepsMut<'_>, name: &RegisteredName) -> NameId {
|
||||
let msg: ExecuteMsg = name.clone().into();
|
||||
let info = mock_info(name.owner.as_str(), &coins(100, "unym"));
|
||||
let res = crate::execute(deps, mock_env(), info, msg).unwrap();
|
||||
let name_id: NameId = get_attribute(&res, &NameEventType::Register.to_string(), NAME_ID)
|
||||
.parse()
|
||||
.unwrap();
|
||||
name_id
|
||||
}
|
||||
|
||||
pub fn delete_name_id(deps: DepsMut<'_>, name_id: NameId, owner: &str) {
|
||||
let msg = ExecuteMsg::DeleteId { name_id };
|
||||
let info = mock_info(owner, &[]);
|
||||
crate::execute(deps, mock_env(), info, msg).unwrap();
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn delete_name(deps: DepsMut<'_>, name: NymName, owner: &str) {
|
||||
let msg = ExecuteMsg::DeleteName { name };
|
||||
let info = mock_info(owner, &[]);
|
||||
crate::execute(deps, mock_env(), info, msg).unwrap();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod assert;
|
||||
pub mod fixture;
|
||||
pub mod helpers;
|
||||
pub mod test_setup;
|
||||
pub mod signing;
|
||||
pub mod transactions;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
use cosmwasm_std::{Addr, Coin, Deps};
|
||||
use nym_contracts_common::signing::{
|
||||
MessageSignature, SignableMessage, SigningAlgorithm, SigningPurpose,
|
||||
};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_name_service_common::{
|
||||
signing_types::{construct_name_register_sign_payload, SignableNameRegisterMsg},
|
||||
NameDetails,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::state;
|
||||
|
||||
pub fn name_register_sign_payload(
|
||||
deps: Deps<'_>,
|
||||
owner: &str,
|
||||
name: NameDetails,
|
||||
deposit: Coin,
|
||||
) -> SignableNameRegisterMsg {
|
||||
let owner = Addr::unchecked(owner);
|
||||
let nonce = state::get_signing_nonce(deps.storage, owner.clone()).unwrap();
|
||||
construct_name_register_sign_payload(nonce, owner, deposit, name)
|
||||
}
|
||||
|
||||
pub fn ed25519_sign_message<T: Serialize + SigningPurpose>(
|
||||
message: SignableMessage<T>,
|
||||
private_key: &identity::PrivateKey,
|
||||
) -> MessageSignature {
|
||||
match message.algorithm {
|
||||
SigningAlgorithm::Ed25519 => {
|
||||
let plaintext = message.to_plaintext().unwrap();
|
||||
let signature = private_key.sign(&plaintext);
|
||||
MessageSignature::from(signature.to_bytes().as_ref())
|
||||
}
|
||||
SigningAlgorithm::Secp256k1 => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
use cosmwasm_std::{
|
||||
coin,
|
||||
testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier},
|
||||
DepsMut, MemoryStorage, OwnedDeps,
|
||||
};
|
||||
use nym_name_service_common::{
|
||||
events::{NameEventType, NAME_ID},
|
||||
msg::{ExecuteMsg, InstantiateMsg},
|
||||
NameDetails, NameId, NymName,
|
||||
};
|
||||
use rand_chacha::rand_core::{CryptoRng, RngCore};
|
||||
|
||||
use super::helpers::{get_attribute, nyms};
|
||||
|
||||
pub fn instantiate_test_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier> {
|
||||
let mut deps = mock_dependencies();
|
||||
let msg = InstantiateMsg {
|
||||
deposit_required: coin(100, "unym"),
|
||||
};
|
||||
let env = mock_env();
|
||||
let info = mock_info("creator", &[]);
|
||||
let res = crate::instantiate(deps.as_mut(), env, info, msg).unwrap();
|
||||
assert_eq!(res.messages.len(), 0);
|
||||
deps
|
||||
}
|
||||
|
||||
pub fn register_name<R>(
|
||||
mut deps: DepsMut<'_>,
|
||||
rng: &mut R,
|
||||
name: &str,
|
||||
nym_address: &str,
|
||||
owner: &str,
|
||||
) -> (NameId, NameDetails)
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let deposit = nyms(100);
|
||||
let (name, owner_signature) = super::fixture::new_name_details_with_sign(
|
||||
deps.branch(),
|
||||
rng,
|
||||
name,
|
||||
nym_address,
|
||||
owner,
|
||||
deposit.clone(),
|
||||
);
|
||||
|
||||
// Register
|
||||
let msg = ExecuteMsg::Register {
|
||||
name: name.clone(),
|
||||
owner_signature,
|
||||
};
|
||||
let info = mock_info(owner, &[deposit]);
|
||||
let res = crate::execute(deps, mock_env(), info, msg).unwrap();
|
||||
|
||||
let name_id: NameId = get_attribute(&res, &NameEventType::Register.to_string(), NAME_ID)
|
||||
.parse()
|
||||
.unwrap();
|
||||
(name_id, name)
|
||||
}
|
||||
|
||||
pub fn delete_name_id(deps: DepsMut<'_>, name_id: NameId, owner: &str) {
|
||||
let msg = ExecuteMsg::DeleteId { name_id };
|
||||
let info = mock_info(owner, &[]);
|
||||
crate::execute(deps, mock_env(), info, msg).unwrap();
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn delete_name(deps: DepsMut<'_>, name: NymName, owner: &str) {
|
||||
let msg = ExecuteMsg::DeleteName { name };
|
||||
let info = mock_info(owner, &[]);
|
||||
crate::execute(deps, mock_env(), info, msg).unwrap();
|
||||
}
|
||||
@@ -593,10 +593,19 @@ nyxd tx slashing unjail
|
||||
|
||||
### Upgrading your validator
|
||||
|
||||
Upgrading from `v0.26.0` -> `v0.31.1` doesn't require many modifications, simply grab a binary from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases) and once the chain has halted at the decided upon haltheight, stop your `nyxd` process, replace your binaries, and restart your process.
|
||||
Upgrading from `v0.26.0` -> `v0.31.1` process is fairly simple. Grab the v0.31.1 release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files:
|
||||
|
||||
- the new validator (`nyxd`) v0.31.1
|
||||
- the new wasmvm (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`)
|
||||
|
||||
Before the upgrade height, copy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`):
|
||||
|
||||
Then just swap in your new `nyxd` binary and restart once the halt height is reached.
|
||||
|
||||
You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/8).
|
||||
|
||||
Note: Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place. Luckily, the name of the wasmvm in v0.26.1 was `libwasmvm.so`, and the new name is `libwasmvm.x86_64.so`, so you can have it already sitting there without disrupting service.
|
||||
|
||||
#### Common reasons for your validator being jailed
|
||||
|
||||
The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs.
|
||||
|
||||
@@ -50,7 +50,7 @@ As seen in the example above, the `mixnet::MixnetClientBuilder::new()` function
|
||||
If you're integrating mixnet functionality into an existing app and want to integrate saving client configs and keys into your existing storage logic, you can manually perform the actions taken automatically above (`examples/manually_handle_keys_and_config.rs`)
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../sdk/rust/nym-sdk/examples/manually_handle_keys_and_config.rs}}
|
||||
{{#include ../../../../sdk/rust/nym-sdk/examples/manually_handle_storage.rs}}
|
||||
```
|
||||
|
||||
### Anonymous replies with SURBs
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
16
|
||||
18
|
||||
|
||||
@@ -22,7 +22,6 @@ pub(crate) mod init;
|
||||
pub(crate) mod node_details;
|
||||
pub(crate) mod run;
|
||||
pub(crate) mod sign;
|
||||
pub(crate) mod upgrade;
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub(crate) enum Commands {
|
||||
@@ -38,9 +37,6 @@ pub(crate) enum Commands {
|
||||
/// Sign text to prove ownership of this mixnode
|
||||
Sign(sign::Sign),
|
||||
|
||||
/// Try to upgrade the gateway
|
||||
Upgrade(upgrade::Upgrade),
|
||||
|
||||
/// Generate shell completions
|
||||
Completions(ArgShell),
|
||||
|
||||
@@ -71,7 +67,6 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
|
||||
Commands::NodeDetails(m) => node_details::execute(m).await?,
|
||||
Commands::Run(m) => run::execute(m).await?,
|
||||
Commands::Sign(m) => sign::execute(m)?,
|
||||
Commands::Upgrade(m) => upgrade::execute(&m).await,
|
||||
Commands::Completions(s) => s.generate(&mut crate::Cli::command(), bin_name),
|
||||
Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name),
|
||||
}
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::Config;
|
||||
use clap::Args;
|
||||
use nym_bin_common::version_checker::Version;
|
||||
use std::fmt::Display;
|
||||
use std::process;
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
pub struct Upgrade {
|
||||
/// Id of the nym-gateway we want to upgrade
|
||||
#[clap(long)]
|
||||
id: String,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||
print_failed_upgrade(from_version, to_version);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
eprintln!(
|
||||
"\n==================\nTrying to upgrade gateway from {} to {} ...",
|
||||
from, to
|
||||
);
|
||||
}
|
||||
|
||||
fn print_failed_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
eprintln!(
|
||||
"Upgrade from {} to {} failed!\n==================\n",
|
||||
from, to
|
||||
);
|
||||
}
|
||||
|
||||
fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
eprintln!(
|
||||
"Upgrade from {} to {} was successful!\n==================\n",
|
||||
from, to
|
||||
);
|
||||
}
|
||||
|
||||
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
|
||||
eprintln!(
|
||||
"Cannot perform upgrade from {} to {}. Your version is too old to perform the upgrade.!",
|
||||
config_version, package_version
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||
eprintln!("Cannot perform upgrade from {} to {}. Please let the developers know about this issue if you expected it to work!", config_version, current_version);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn parse_config_version(config: &Config) -> Version {
|
||||
let version = Version::parse(&config.gateway.version).unwrap_or_else(|err| {
|
||||
eprintln!("failed to parse client version! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!(
|
||||
"Trying to upgrade from a non-released version {}. This is not supported!",
|
||||
version
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn parse_package_version() -> Version {
|
||||
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
||||
|
||||
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
|
||||
// however, we are not using them ourselves at the moment and hence it should be fine.
|
||||
// if we change our mind, we could easily tweak this code
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!(
|
||||
"Trying to upgrade to a non-released version {}. This is not supported!",
|
||||
version
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn minor_0_12_upgrade(
|
||||
config: Config,
|
||||
_args: &Upgrade,
|
||||
config_version: &Version,
|
||||
package_version: &Version,
|
||||
) -> Config {
|
||||
let to_version = if package_version.major == 0 && package_version.minor == 12 {
|
||||
package_version.clone()
|
||||
} else {
|
||||
Version::new(0, 12, 0)
|
||||
};
|
||||
|
||||
print_start_upgrade(config_version, &to_version);
|
||||
|
||||
let upgraded_config = config.with_custom_version(to_version.to_string());
|
||||
|
||||
upgraded_config
|
||||
.save_to_default_location()
|
||||
.unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {err}");
|
||||
print_failed_upgrade(config_version, &to_version);
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
print_successful_upgrade(config_version, to_version);
|
||||
|
||||
upgraded_config
|
||||
}
|
||||
|
||||
fn do_upgrade(mut config: Config, args: &Upgrade, package_version: Version) {
|
||||
loop {
|
||||
let config_version = parse_config_version(&config);
|
||||
|
||||
if config_version == package_version {
|
||||
eprintln!("You're using the most recent version!");
|
||||
return;
|
||||
}
|
||||
|
||||
config = match config_version.major {
|
||||
0 => match config_version.minor {
|
||||
9 | 10 => outdated_upgrade(&config_version, &package_version),
|
||||
11 => minor_0_12_upgrade(config, args, &config_version, &package_version),
|
||||
_ => unsupported_upgrade(&config_version, &package_version),
|
||||
},
|
||||
_ => unsupported_upgrade(&config_version, &package_version),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn execute(args: &Upgrade) {
|
||||
let package_version = parse_package_version();
|
||||
|
||||
let existing_config = Config::read_from_default_path(&args.id).unwrap_or_else(|err| {
|
||||
eprintln!("failed to load existing config file! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if existing_config.gateway.version.is_empty() {
|
||||
eprintln!("the existing configuration file does not seem to contain version number.");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
do_upgrade(existing_config, args, package_version)
|
||||
}
|
||||
@@ -159,11 +159,6 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_custom_version<S: Into<String>>(mut self, version: S) -> Self {
|
||||
self.gateway.version = version.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_statistics_service_url(&self) -> Url {
|
||||
self.gateway.statistics_service_url.clone()
|
||||
}
|
||||
|
||||
+2
-8
@@ -1,10 +1,4 @@
|
||||
{
|
||||
"packages": [
|
||||
"ts-packages/*",
|
||||
"nym-wallet",
|
||||
"nym-connect/**",
|
||||
"sdk/typescript/examples/docs",
|
||||
"sdk/typescript/packages/**"
|
||||
],
|
||||
"version": "0.0.0"
|
||||
"version": "0.0.0",
|
||||
"useWorkspaces": true
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ mod init;
|
||||
mod node_details;
|
||||
mod run;
|
||||
mod sign;
|
||||
mod upgrade;
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub(crate) enum Commands {
|
||||
@@ -36,9 +35,6 @@ pub(crate) enum Commands {
|
||||
/// Sign text to prove ownership of this mixnode
|
||||
Sign(sign::Sign),
|
||||
|
||||
/// Try to upgrade the mixnode
|
||||
Upgrade(upgrade::Upgrade),
|
||||
|
||||
/// Show details of this mixnode
|
||||
NodeDetails(node_details::NodeDetails),
|
||||
|
||||
@@ -67,7 +63,6 @@ pub(crate) async fn execute(args: Cli) -> anyhow::Result<()> {
|
||||
Commands::Init(m) => init::execute(&m),
|
||||
Commands::Run(m) => run::execute(&m).await?,
|
||||
Commands::Sign(m) => sign::execute(&m)?,
|
||||
Commands::Upgrade(m) => upgrade::execute(&m)?,
|
||||
Commands::NodeDetails(m) => node_details::execute(&m)?,
|
||||
Commands::Completions(s) => s.generate(&mut crate::Cli::command(), bin_name),
|
||||
Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name),
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_upgrade_v1_1_21_config;
|
||||
use crate::config::Config;
|
||||
use clap::Args;
|
||||
use nym_bin_common::version_checker::Version;
|
||||
use std::fmt::Display;
|
||||
use std::process;
|
||||
|
||||
#[derive(Args)]
|
||||
pub(crate) struct Upgrade {
|
||||
/// Id of the nym-mixnode we want to upgrade
|
||||
#[clap(long)]
|
||||
id: String,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||
print_failed_upgrade(from_version, to_version);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
println!("\n==================\nTrying to upgrade mixnode from {from} to {to} ...");
|
||||
}
|
||||
|
||||
fn print_failed_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
eprintln!("Upgrade from {from} to {to} failed!\n==================\n");
|
||||
}
|
||||
|
||||
fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
println!("Upgrade from {from} to {to} was successful!\n==================\n");
|
||||
}
|
||||
|
||||
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
|
||||
eprintln!(
|
||||
"Cannot perform upgrade from {config_version} to {package_version}. Your version is too old to perform the upgrade.!"
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn unsupported_upgrade(config_version: &Version, package_version: &Version) -> ! {
|
||||
eprintln!("Cannot perform upgrade from {config_version} to {package_version}. Please let the developers know about this issue if you expected it to work!");
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn parse_config_version(config: &Config) -> Version {
|
||||
let version = Version::parse(&config.mixnode.version).unwrap_or_else(|err| {
|
||||
eprintln!("failed to parse client version! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!(
|
||||
"Trying to upgrade from a non-released version {version}. This is not supported!"
|
||||
);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn parse_package_version() -> Version {
|
||||
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
||||
|
||||
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
|
||||
// however, we are not using them ourselves at the moment and hence it should be fine.
|
||||
// if we change our mind, we could easily tweak this code
|
||||
if version.is_prerelease() || !version.build.is_empty() {
|
||||
eprintln!("Trying to upgrade to a non-released version {version}. This is not supported!");
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
version
|
||||
}
|
||||
|
||||
fn minor_0_12_upgrade(
|
||||
config: Config,
|
||||
_args: &Upgrade,
|
||||
config_version: &Version,
|
||||
package_version: &Version,
|
||||
) -> Config {
|
||||
let to_version = if package_version.major == 0 && package_version.minor == 12 {
|
||||
package_version.clone()
|
||||
} else {
|
||||
Version::new(0, 12, 0)
|
||||
};
|
||||
|
||||
print_start_upgrade(config_version, &to_version);
|
||||
|
||||
let upgraded_config = config.with_custom_version(to_version.to_string());
|
||||
|
||||
upgraded_config
|
||||
.save_to_default_location()
|
||||
.unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {err}");
|
||||
print_failed_upgrade(config_version, &to_version);
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
print_successful_upgrade(config_version, to_version);
|
||||
|
||||
upgraded_config
|
||||
}
|
||||
|
||||
fn do_upgrade(mut config: Config, args: &Upgrade, package_version: Version) {
|
||||
loop {
|
||||
let config_version = parse_config_version(&config);
|
||||
|
||||
if config_version == package_version {
|
||||
println!("You're using the most recent version!");
|
||||
return;
|
||||
}
|
||||
|
||||
config = match config_version.major {
|
||||
0 => match config_version.minor {
|
||||
9 | 10 => outdated_upgrade(&config_version, &package_version),
|
||||
11 => minor_0_12_upgrade(config, args, &config_version, &package_version),
|
||||
_ => unsupported_upgrade(&config_version, &package_version),
|
||||
},
|
||||
_ => unsupported_upgrade(&config_version, &package_version),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn execute(args: &Upgrade) -> anyhow::Result<()> {
|
||||
try_upgrade_v1_1_21_config(&args.id)?;
|
||||
|
||||
let package_version = parse_package_version();
|
||||
|
||||
let existing_config = Config::read_from_default_path(&args.id).unwrap_or_else(|err| {
|
||||
eprintln!("failed to load existing config file! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
if existing_config.mixnode.version.is_empty() {
|
||||
eprintln!("the existing configuration file does not seem to contain version number.");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
do_upgrade(existing_config, args, package_version);
|
||||
Ok(())
|
||||
}
|
||||
@@ -147,11 +147,6 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_custom_version<S: Into<String>>(mut self, version: S) -> Self {
|
||||
self.mixnode.version = version.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
|
||||
self.mixnode.nym_api_urls.clone()
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ use nym_mixnet_contract_common::{
|
||||
families::FamilyHead, GatewayBond, IdentityKey, Interval, MixId, MixNodeDetails,
|
||||
RewardingParams,
|
||||
};
|
||||
use nym_name_service_common::NameEntry;
|
||||
use nym_name_service_common::RegisteredName;
|
||||
use nym_service_provider_directory_common::Service;
|
||||
use std::collections::HashSet;
|
||||
|
||||
@@ -26,7 +26,7 @@ pub(crate) struct ValidatorCacheData {
|
||||
pub(crate) mix_to_family: Cache<Vec<(IdentityKey, FamilyHead)>>,
|
||||
|
||||
pub(crate) service_providers: Cache<Vec<Service>>,
|
||||
pub(crate) registered_names: Cache<Vec<NameEntry>>,
|
||||
pub(crate) registered_names: Cache<Vec<RegisteredName>>,
|
||||
}
|
||||
|
||||
impl ValidatorCacheData {
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@ use nym_mixnet_contract_common::{
|
||||
families::FamilyHead, GatewayBond, IdentityKey, Interval, MixId, MixNodeBond, MixNodeDetails,
|
||||
RewardingParams,
|
||||
};
|
||||
use nym_name_service_common::NameEntry;
|
||||
use nym_name_service_common::RegisteredName;
|
||||
use nym_service_provider_directory_common::Service;
|
||||
use rocket::fairing::AdHoc;
|
||||
use std::{
|
||||
@@ -53,7 +53,7 @@ impl NymContractCache {
|
||||
current_interval: Interval,
|
||||
mix_to_family: Vec<(IdentityKey, FamilyHead)>,
|
||||
services: Option<Vec<Service>>,
|
||||
names: Option<Vec<NameEntry>>,
|
||||
names: Option<Vec<RegisteredName>>,
|
||||
) {
|
||||
match time::timeout(Duration::from_millis(100), self.inner.write()).await {
|
||||
Ok(mut cache) => {
|
||||
@@ -303,7 +303,7 @@ impl NymContractCache {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn names(&self) -> Cache<Vec<NameEntry>> {
|
||||
pub(crate) async fn names(&self) -> Cache<Vec<RegisteredName>> {
|
||||
match time::timeout(Duration::from_millis(100), self.inner.read()).await {
|
||||
Ok(cache) => cache.registered_names.clone(),
|
||||
Err(err) => {
|
||||
|
||||
@@ -1 +1 @@
|
||||
14
|
||||
18
|
||||
Generated
+4
@@ -3564,8 +3564,12 @@ name = "nym-name-service-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"cw-controllers",
|
||||
"cw-utils",
|
||||
"nym-contracts-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -30,19 +30,7 @@ pub enum Socks5ExitStatusMessage {
|
||||
Failed(Box<dyn std::error::Error + Send>),
|
||||
}
|
||||
|
||||
/// The main SOCKS5 client task. It loads the configuration from file determined by the `id`.
|
||||
pub async fn start_nym_socks5_client(
|
||||
id: &str,
|
||||
) -> Result<(
|
||||
Socks5ControlMessageSender,
|
||||
nym_task::StatusReceiver,
|
||||
ExitStatusReceiver,
|
||||
GatewayEndpointConfig,
|
||||
)> {
|
||||
log::info!("Loading config from file: {id}");
|
||||
let mut config = Config::read_from_default_path(id)
|
||||
.tap_err(|_| log::warn!("Failed to load configuration file"))?;
|
||||
|
||||
fn override_config_from_env(config: &mut Config) {
|
||||
// Disable both the loop cover traffic that runs in the background as well as the Poisson
|
||||
// process that injects cover traffic into the traffic stream.
|
||||
if std::env::var("NYM_CONNECT_DISABLE_COVER").is_ok() {
|
||||
@@ -62,6 +50,22 @@ pub async fn start_nym_socks5_client(
|
||||
log::warn!("Disabling per-hop delay");
|
||||
config.core.base.set_no_per_hop_delays();
|
||||
}
|
||||
}
|
||||
|
||||
/// The main SOCKS5 client task. It loads the configuration from file determined by the `id`.
|
||||
pub async fn start_nym_socks5_client(
|
||||
id: &str,
|
||||
) -> Result<(
|
||||
Socks5ControlMessageSender,
|
||||
nym_task::StatusReceiver,
|
||||
ExitStatusReceiver,
|
||||
GatewayEndpointConfig,
|
||||
)> {
|
||||
log::info!("Loading config from file: {id}");
|
||||
let mut config = Config::read_from_default_path(id)
|
||||
.tap_err(|_| log::warn!("Failed to load configuration file"))?;
|
||||
|
||||
override_config_from_env(&mut config);
|
||||
|
||||
log::trace!("Configuration used: {:#?}", config);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Apps, HelpOutline, Settings } from '@mui/icons-material';
|
||||
import { Apps, HelpOutline, Settings, BugReport } from '@mui/icons-material';
|
||||
import { Stack, Link, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { AppVersion } from 'src/components/AppVersion';
|
||||
@@ -7,6 +7,7 @@ import { AppVersion } from 'src/components/AppVersion';
|
||||
const menuSchema = [
|
||||
{ title: 'Supported apps', icon: Apps, path: 'apps' },
|
||||
{ title: 'How to connect guide', icon: HelpOutline, path: 'guide' },
|
||||
{ title: 'Please help us improve the app', icon: BugReport, path: 'monitoring' },
|
||||
{ title: 'Settings', icon: Settings, path: 'settings' },
|
||||
];
|
||||
|
||||
|
||||
@@ -34,10 +34,6 @@ export const MonitoringSettings = () => {
|
||||
occur or if the app crashes, it will automatically send a report. Also it tracks various performance
|
||||
metrics. We use sentry.io service to handle this.
|
||||
</FormHelperText>
|
||||
<FormHelperText sx={{ m: 0, mb: 2 }}>
|
||||
Note: A report can include your external IP, this can be useful to catch issues related to IP location.
|
||||
All recorded data is used by Nym developers and for app development purposes only.
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
<Stack direction="row" gap={1} alignItems="center">
|
||||
<WarningIcon color="warning" fontSize="small" />
|
||||
|
||||
@@ -7,7 +7,6 @@ import { toggleLogViewer } from 'src/utils';
|
||||
const menuSchema = [
|
||||
{ title: 'Select your gateway', path: 'gateway' },
|
||||
{ title: 'Select a service provider', path: 'service-provider' },
|
||||
{ title: 'Help improve the app', path: 'monitoring' },
|
||||
];
|
||||
|
||||
export const SettingsMenu = () => (
|
||||
|
||||
@@ -25,11 +25,11 @@ export const AppRoutes = () => {
|
||||
<Route index element={<Menu />} />
|
||||
<Route path="apps" element={<CompatibleApps />} />
|
||||
<Route path="guide" element={<HelpGuide />} />
|
||||
<Route path="monitoring" element={<MonitoringSettings />} />
|
||||
<Route path="settings">
|
||||
<Route index element={<SettingsMenu />} />
|
||||
<Route path="gateway" element={<GatewaySettings />} />
|
||||
<Route path="service-provider" element={<ServiceProviderSettings />} />
|
||||
<Route path="monitoring" element={<MonitoringSettings />} />
|
||||
</Route>
|
||||
</Route>
|
||||
</RoutesContainer>
|
||||
|
||||
@@ -43,6 +43,8 @@ async function initSentry() {
|
||||
getVersion().then((version) => {
|
||||
Sentry.setTag('app_version', version);
|
||||
});
|
||||
|
||||
Sentry.setUser({ id: 'nym', ip_address: undefined });
|
||||
}
|
||||
|
||||
export default initSentry;
|
||||
|
||||
@@ -1 +1 @@
|
||||
14
|
||||
18
|
||||
@@ -99,7 +99,6 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.10.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
|
||||
implementation 'androidx.activity:activity-compose:1.7.2'
|
||||
@@ -124,4 +123,5 @@ dependencies {
|
||||
debugImplementation 'androidx.compose.ui:ui-tooling'
|
||||
debugImplementation 'androidx.compose.ui:ui-test-manifest'
|
||||
implementation 'com.github.kittinunf.fuel:fuel:3.0.0-alpha1'
|
||||
implementation 'io.sentry:sentry-android:6.24.0'
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package net.nymtech.nyms5
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
@@ -9,11 +11,15 @@ import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import androidx.work.Configuration
|
||||
import androidx.work.DelegatingWorkerFactory
|
||||
import io.sentry.Scope
|
||||
import io.sentry.Sentry
|
||||
import io.sentry.android.core.SentryAndroid
|
||||
import io.sentry.protocol.User
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
|
||||
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
||||
val monitoringKey = booleanPreferencesKey("monitoring")
|
||||
|
||||
@@ -40,11 +46,34 @@ class App : Application(), Configuration.Provider {
|
||||
options.dsn =
|
||||
"https://6872f5818bc147ef9c0fce114fcaac8a@o967446.ingest.sentry.io/4505306218102784"
|
||||
options.enableAllAutoBreadcrumbs(true)
|
||||
options.isEnableUserInteractionTracing = true
|
||||
options.isEnableUserInteractionBreadcrumbs = true
|
||||
|
||||
// TODO should be adjusted in production env
|
||||
options.sampleRate = 1.0
|
||||
options.tracesSampleRate = 1.0
|
||||
options.profilesSampleRate = 1.0
|
||||
}
|
||||
|
||||
Sentry.configureScope { scope: Scope ->
|
||||
val packageManager = applicationContext.packageManager
|
||||
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
packageManager.getPackageInfo(
|
||||
packageName,
|
||||
PackageManager.PackageInfoFlags.of(0)
|
||||
)
|
||||
} else {
|
||||
packageManager.getPackageInfo(packageName, 0)
|
||||
}
|
||||
scope.setTag("app_version", packageInfo.versionName)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
scope.setTag("app_version_code", packageInfo.longVersionCode.toString())
|
||||
}
|
||||
}
|
||||
|
||||
val user = User()
|
||||
user.id = "nym"
|
||||
Sentry.setUser(user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
@@ -249,7 +250,7 @@ fun S5ClientSwitch(
|
||||
Spacer(modifier = modifier.width(14.dp))
|
||||
Switch(checked = connected, enabled = !loading, onCheckedChange = {
|
||||
onSwitch(!connected)
|
||||
})
|
||||
}, modifier = Modifier.testTag("switch_connect"))
|
||||
}
|
||||
if (connected && !loading) {
|
||||
Column(modifier = modifier.padding(16.dp)) {
|
||||
@@ -332,12 +333,10 @@ fun Monitoring(
|
||||
tint = Color.Yellow
|
||||
)
|
||||
Spacer(modifier = modifier.width(16.dp))
|
||||
Text(stringResource(R.string.monitoring_desc_3), color = Color.Yellow)
|
||||
Text(stringResource(R.string.monitoring_desc_2), color = Color.Yellow)
|
||||
}
|
||||
Spacer(modifier = modifier.height(18.dp))
|
||||
Text(stringResource(R.string.monitoring_desc_1))
|
||||
Spacer(modifier = modifier.height(18.dp))
|
||||
Text(stringResource(R.string.monitoring_desc_2))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.nymtech.nyms5
|
||||
|
||||
import android.util.Log
|
||||
import io.sentry.Sentry
|
||||
|
||||
const val nymNativeLib = "nym_socks5_listener"
|
||||
|
||||
@@ -27,6 +28,7 @@ class NymProxy {
|
||||
startClient(serviceProvider, onStartCbObj, onStopCbObj)
|
||||
} catch (e: Throwable) {
|
||||
Log.e(tag, "$nymNativeLib:startClient internal error: $e")
|
||||
Sentry.captureException(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +38,7 @@ class NymProxy {
|
||||
stopClient()
|
||||
} catch (e: Throwable) {
|
||||
Log.e(tag, "$nymNativeLib:stopClient internal error: $e")
|
||||
Sentry.captureException(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +53,7 @@ class NymProxy {
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Log.e(tag, "$nymNativeLib:getClientState internal error: $e")
|
||||
Sentry.captureException(e)
|
||||
}
|
||||
return State.UNINITIALIZED
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user