Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 63254ecffe | |||
| 407d280019 | |||
| 1fafc126fb | |||
| 9a51135d22 | |||
| 1b2790da80 | |||
| f8943eebce | |||
| d7b53cba40 | |||
| 89d2f0ac12 | |||
| 110b4d384e | |||
| 4631c72c6b | |||
| 12aa5f1f4f | |||
| 825f25800a | |||
| d9b4d8fde6 | |||
| a98613d83c | |||
| c6b193eb4f | |||
| a881740c20 | |||
| 90cc68435c | |||
| c3ce9e24e2 | |||
| bdda08c0b4 | |||
| 0e48ff5e9e | |||
| 68d6ece6c2 | |||
| e17ae9dce0 | |||
| 493f036687 | |||
| 1f4f312e8e | |||
| d829837275 | |||
| 36253e3f36 | |||
| 7743554bb8 | |||
| de05e32845 | |||
| 136f4a8473 | |||
| 57e2628928 | |||
| 879e324696 | |||
| 351552b863 | |||
| 847f3a0ecc | |||
| 58958a2449 | |||
| 3051d84e8d | |||
| 2d7003dfae | |||
| 92b9edf0da | |||
| a91c997aed | |||
| 5787653210 | |||
| adbeeb3e5f | |||
| 4899ccf4ef | |||
| 9e0bcc025f | |||
| 16d6444169 | |||
| 997faeb1e6 | |||
| 565e7768e3 | |||
| 730f03de30 | |||
| 2e366a094d | |||
| b134334ec7 | |||
| f95b9b7f4a | |||
| 11ed3b3e45 | |||
| 271a5fbab6 | |||
| 90a97b398e | |||
| fc2236c3c8 | |||
| a71e228a25 | |||
| da9c2e5a7c | |||
| e025564678 | |||
| cf6188d794 | |||
| dd7308d92f | |||
| 73ca14aae2 | |||
| 0fee189a89 | |||
| a0c6efafd2 | |||
| c3d3164533 | |||
| fa2e0a9010 | |||
| fcc5398aab | |||
| 9f1f765f73 | |||
| 6403d0055b | |||
| 7bbb10e52c | |||
| 1aad69a527 | |||
| 4ad02d5328 | |||
| 45b74008f1 | |||
| 2ddf9646ec | |||
| b258cd8733 | |||
| ed48a2ddd4 | |||
| 7a1a7c003e | |||
| ef36c29b91 | |||
| 4025fed882 | |||
| 9aaa74204b | |||
| 9d7a6b2aec | |||
| 4b13a5cf61 | |||
| c9489fb48e | |||
| 6c3653c128 | |||
| 02a4452eca | |||
| d47633faa8 | |||
| a3da077ce9 | |||
| 131952c036 | |||
| 8d2ef605ed | |||
| fbcc2907bb | |||
| c0bb5503cf | |||
| ef7beaa12f | |||
| 2953837f25 | |||
| ee98820bb4 | |||
| 0f41dda013 | |||
| 51d66c3e0c | |||
| f14b40a769 | |||
| d8f80434b4 | |||
| 2f98912778 |
@@ -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,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: Build
|
||||
|
||||
@@ -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,11 +20,17 @@ 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
|
||||
|
||||
- name: Install project dependencies
|
||||
run: cd ../.. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
continue-on-error: true
|
||||
|
||||
- name: Set environment from the example
|
||||
run: cp .env.sample .env
|
||||
- run: yarn storybook:build
|
||||
|
||||
@@ -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
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -51,11 +58,15 @@ jobs:
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies and build it
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -73,7 +84,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect_1.0.0_x64.dmg
|
||||
path: nym-connect/desktop/target/release/bundle/dmg/nym-connect_1.0.0_x64.dmg
|
||||
path: nym-connect/desktop/target/release/bundle/dmg/nym-connect_1*_x64.dmg
|
||||
retention-days: 30
|
||||
|
||||
- name: Clean up keychain
|
||||
@@ -81,10 +92,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
|
||||
|
||||
@@ -26,19 +33,25 @@ jobs:
|
||||
sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev
|
||||
continue-on-error: true
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
@@ -53,13 +66,41 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect.AppImage.tar.gz
|
||||
path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage
|
||||
path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1*_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
|
||||
@@ -39,10 +46,10 @@ jobs:
|
||||
Remove-Item -path certificate -include tempCert.txt
|
||||
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -50,15 +57,21 @@ jobs:
|
||||
toolchain: stable
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies
|
||||
shell: bash
|
||||
run: yarn --network-timeout 100000
|
||||
|
||||
- name: Build and sign it
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
@@ -72,13 +85,41 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect_1.0.0_x64_en-US.msi
|
||||
path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi
|
||||
path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1*_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
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -51,11 +58,15 @@ jobs:
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies and build it
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -80,11 +91,40 @@ 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: |
|
||||
ref=${{ github.ref_name }}
|
||||
semver="${ref##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
|
||||
|
||||
@@ -25,19 +33,24 @@ jobs:
|
||||
sudo apt-get install -y webkit2gtk-4.0
|
||||
continue-on-error: true
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
@@ -47,9 +60,48 @@ jobs:
|
||||
env:
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
- name: Upload to release based on tag name
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-wallet_1.0.0_amd64.AppImage.tar.gz
|
||||
path: nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz
|
||||
retention-days: 30
|
||||
|
||||
- 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/appimage/*.AppImage
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz*
|
||||
|
||||
- id: release-info
|
||||
name: Prepare release info
|
||||
run: |
|
||||
ref=${{ github.ref_name }}
|
||||
semver="${ref##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
|
||||
@@ -39,10 +46,10 @@ jobs:
|
||||
Remove-Item -path certificate -include tempCert.txt
|
||||
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -50,15 +57,21 @@ jobs:
|
||||
toolchain: stable
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies
|
||||
shell: bash
|
||||
run: yarn --network-timeout 100000
|
||||
|
||||
- name: Build and sign it
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
@@ -75,10 +88,40 @@ 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: |
|
||||
ref=${{ github.ref_name }}
|
||||
semver="${ref##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
|
||||
|
||||
@@ -34,10 +34,10 @@ jobs:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install yarn for building application
|
||||
run: yarn install
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
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,35 @@
|
||||
name: Publish SDK to NPM
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: [custom-runner-linux]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- 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: Install dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Build and publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
|
||||
working-directory: ./sdk/typescript/packages/sdk
|
||||
run: scripts/publish.sh
|
||||
@@ -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,19 +35,9 @@ 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
|
||||
working-directory: clients/webassembly
|
||||
- name: Build WASM
|
||||
run: wasm-pack build
|
||||
working-directory: clients/webassembly
|
||||
- name: Install
|
||||
run: yarn
|
||||
- name: Build packages
|
||||
|
||||
+5
-1
@@ -4,12 +4,16 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.1.23] (2023-06-27)
|
||||
## [v1.1.23] (2023-07-04)
|
||||
|
||||
- nym-cli: add client identity key signing support ([#3576])
|
||||
- Feature/node tester package ([#3634])
|
||||
- Add medium toggle to socks5 client ([#3615])
|
||||
- Don't fully turn off background task when cover traffic is disabled ([#3596])
|
||||
|
||||
[#3576]: https://github.com/nymtech/nym/issues/3576
|
||||
[#3634]: https://github.com/nymtech/nym/pull/3634
|
||||
[#3615]: https://github.com/nymtech/nym/pull/3615
|
||||
[#3596]: https://github.com/nymtech/nym/pull/3596
|
||||
|
||||
## [v1.1.22] (2023-06-20)
|
||||
|
||||
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"
|
||||
|
||||
@@ -13,7 +13,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
* nym-gateway - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices.
|
||||
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
||||
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
|
||||
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
||||
@@ -21,7 +21,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
|
||||
### Building
|
||||
|
||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/build-nym.html).
|
||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/pre-built-binaries.html).
|
||||
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/wallet/desktop-wallet.html).
|
||||
|
||||
### Developing
|
||||
@@ -32,9 +32,9 @@ For Typescript components, please see [ts-packages](./ts-packages).
|
||||
|
||||
### Developer chat
|
||||
|
||||
> We used to use Keybase for developer chats, but we have since migrated to Matrix and Discord. We no longer check the old **nymtech.friends** Keybase team.
|
||||
> We used to use Keybase for developer chats, but we have since migrated to Matrix and Discord. We no longer check the old **nymtech.friends** Keybase team.
|
||||
|
||||
You can chat to us in two places:
|
||||
You can chat to us in two places:
|
||||
* The #dev channel on [Matrix](https://matrix.to/#/#dev:nymtech.chat)
|
||||
* The various developer channels on [Discord](https://discord.gg/nym)
|
||||
|
||||
@@ -84,4 +84,3 @@ where `s'` is stake `s` scaled over total token circulating supply.
|
||||
### Licensing and copyright information
|
||||
|
||||
This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -94,6 +94,7 @@ impl From<Init> for OverrideConfig {
|
||||
use_anonymous_replies: init_config.use_reply_surbs,
|
||||
fastmode: init_config.fastmode,
|
||||
no_cover: init_config.no_cover,
|
||||
medium_toggle: false,
|
||||
nyxd_urls: init_config.nyxd_urls,
|
||||
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
||||
outfox: false,
|
||||
|
||||
@@ -19,7 +19,7 @@ use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
use nym_config::OptionalSet;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use std::error::Error;
|
||||
|
||||
pub mod init;
|
||||
@@ -68,6 +68,7 @@ pub(crate) struct OverrideConfig {
|
||||
use_anonymous_replies: Option<bool>,
|
||||
fastmode: bool,
|
||||
no_cover: bool,
|
||||
medium_toggle: bool,
|
||||
nyxd_urls: Option<Vec<url::Url>>,
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
outfox: bool,
|
||||
@@ -86,6 +87,10 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Syn
|
||||
}
|
||||
|
||||
pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
let disable_cover_traffic_with_keepalive = args.medium_toggle;
|
||||
let secondary_packet_size = args.medium_toggle.then_some(PacketSize::ExtendedPacket16);
|
||||
let no_per_hop_delays = args.medium_toggle;
|
||||
|
||||
let packet_type = if args.outfox {
|
||||
PacketType::Outfox
|
||||
} else {
|
||||
@@ -96,6 +101,17 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
BaseClientConfig::with_high_default_traffic_volume,
|
||||
args.fastmode,
|
||||
)
|
||||
.with_base(
|
||||
// NOTE: This interacts with disabling cover traffic fully, so we want to this to be set before
|
||||
BaseClientConfig::with_disabled_cover_traffic_with_keepalive,
|
||||
disable_cover_traffic_with_keepalive,
|
||||
)
|
||||
.with_base(
|
||||
BaseClientConfig::with_secondary_packet_size,
|
||||
secondary_packet_size,
|
||||
)
|
||||
.with_base(BaseClientConfig::with_no_per_hop_delays, no_per_hop_delays)
|
||||
// NOTE: see comment above about the order of the other disble cover traffic config
|
||||
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
|
||||
.with_base(BaseClientConfig::with_packet_type, packet_type)
|
||||
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
|
||||
|
||||
@@ -60,6 +60,11 @@ pub(crate) struct Run {
|
||||
#[clap(long, hide = true)]
|
||||
no_cover: bool,
|
||||
|
||||
/// Enable medium mixnet traffic, for experiments only.
|
||||
/// This includes things like disabling cover traffic, no per hop delays, etc.
|
||||
#[clap(long, hide = true)]
|
||||
medium_toggle: bool,
|
||||
|
||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||
/// with bandwidth credential requirement.
|
||||
#[clap(long, hide = true)]
|
||||
@@ -77,6 +82,7 @@ impl From<Run> for OverrideConfig {
|
||||
use_anonymous_replies: run_config.use_anonymous_replies,
|
||||
fastmode: run_config.fastmode,
|
||||
no_cover: run_config.no_cover,
|
||||
medium_toggle: run_config.medium_toggle,
|
||||
nyxd_urls: run_config.nyxd_urls,
|
||||
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
||||
outfox: run_config.outfox,
|
||||
|
||||
@@ -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 }
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -79,7 +79,7 @@ copy-fonts = true
|
||||
no-section-label = false
|
||||
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"]
|
||||
additional-js = ["theme/pagetoc.js"]
|
||||
git-repository-url = "https://github.com/nymtech/dev-portal"
|
||||
git-repository-url = "https://github.com/nymtech/nym"
|
||||
git-repository-icon = "fa-github"
|
||||
# edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}"
|
||||
site-url = "/developers/"
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
- [SOCKS Proxy (CLI)](quickstart/socks-proxy.md)
|
||||
- [NymConnect Beta (GUI)](quickstart/nymconnect-gui.md)
|
||||
|
||||
# User Manuals
|
||||
|
||||
- [NymConnect Monero](tutorials/monero.md)
|
||||
- [NymConnect Matrix](tutorials/matrix.md)
|
||||
|
||||
# Integrations
|
||||
|
||||
- [Integration Options](integrations/integration-options.md)
|
||||
@@ -35,14 +40,13 @@
|
||||
# Community Resources
|
||||
|
||||
- [Nym DevRel AMAs](community-resources/ama.md)
|
||||
- [Community Applications](community-resources/community-applications.md)
|
||||
- [Community Guides](community-resources/community-guides.md)
|
||||
- [Community Applications and Guides](community-resources/community-applications-and-guides.md)
|
||||
- [Change Service Grantee Information](info-request.md)
|
||||
- [Rewards FAQ](community-resources/rewards-faq.md)
|
||||
---
|
||||
---
|
||||
|
||||
# Misc.
|
||||
- [Glossary](glossary.md)
|
||||
- [Code of Conduct](coc.md)
|
||||
- [Licensing](licensing.md)
|
||||
---
|
||||
---
|
||||
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
# Community Applications
|
||||
|
||||
We love seeing our developer community create applications using Nym. If you would like to share your application with the community, please submit a pull request to the `main` branch of the `nymtech/dev-portal` [repository](https://github.com/nymtech/dev-portal).
|
||||
|
||||
|
||||
|
||||
## <img src='../images/profile_picture/pastenym_ntv_pp.png' style="float: right; width: 75px; height: 75px;">Pastenym
|
||||
|
||||
>A [pastebin](https://pastebin.com) inspired project, offer a solution for sharing text with Nym products to offer full anonymity, even on metadata level.
|
||||
|
||||
* [Github](https://github.com/notrustverify/pastenym)
|
||||
* [Deployed App](https://pastenym.ch)
|
||||
|
||||
|
||||
|
||||
|
||||
## <img src='../images/profile_picture/pineappleproxy_pp.png' style="float: right; width: 75px; height: 75px;">Nostr-Nym
|
||||
|
||||
> [Nostr-nym](https://github.com/notrustverify/nostr-nym) offer a solution to use [Nostr](https://nostr.how/en/what-is-nostr) protocol by giving the possibility to run a relay on mixnet. By using a nostr client compatible with the mixnet, users can protect their privacy to be able to use Nostr has the want, without being observed.
|
||||
|
||||
* [Github](https://github.com/notrustverify/nostr-nym)
|
||||
* [Deployed App](https://nostrnym.pnproxy.org/)
|
||||
* [Documentation](https://blog.notrustverify.ch/nostr-relay-on-nym)
|
||||
|
||||
|
||||
|
||||
|
||||
## <img src='../images/profile_picture/ethereum_rpc_spook_pp.png' style="float: right; width: 75px; height: 75px;"> Spook
|
||||
|
||||
> Ethereum RPC request mixer uses the Nym network mixing service to anonymize RPC requests to the Ethereum network without revealing sensitive data and metadata.
|
||||
* [Github](https://github.com/EdenBlockVC/spook)
|
||||
|
||||
|
||||
|
||||
|
||||
## <img src='../images/profile_picture/ethereum_transaction_broadcaster_root_pp.png' style="float: right; width: 75px; height: 75px;"> Ethereum Transaction Broadcaster
|
||||
|
||||
> Ethereum Transaction Broadcaster that uses the Nym Mixnet to provide privacy and anonymity for transactions on the Ethereum network command-line interface.
|
||||
|
||||
* [Github](https://github.com/noot/nym-ethtx)
|
||||
|
||||
|
||||
|
||||
|
||||
## <img src='../images/profile_picture/nymdrive_saleel_pp.png' style="float: right; width: 75px; height: 75px;">NymDrive
|
||||
|
||||
> An open-source, decentralized, E2E encrypted, privacy friendly alternative to Google Drive/Dropbox, allowing for file encryption and decryption using the Nym Mixnet.
|
||||
* [Github](https://github.com/saleel/nymdrive)
|
||||
* [Demo](https://www.youtube.com/watch?v=5Rx73nw8NYI)
|
||||
* [Presentation](https://docs.google.com/presentation/d/1MpvIK32Mx9VKLVfMTcvbeyrsKHHUsTvDQ-3n31dR0NE/edit#slide=id.p)
|
||||
|
||||
|
||||
|
||||
|
||||
## <img src='../images/profile_picture/nym_dashboard_pp.svg' style="float: right; width: 75px; height: 75px;">Nym Dashboard
|
||||
|
||||
> Developed by No Trust Verify, this dashboard is a great tool to get information about the mixnet, gateways and mixnodes.
|
||||
* [Deployed App](https://status.notrustverify.ch/d/CW3L7dVVk/nym-mixnet?orgId=1)
|
||||
|
||||
|
||||
|
||||
|
||||
## <img src='../images/profile_picture/pastenym_ntv_pp.png' style="float: right; width: 75px; height: 75px;">Is Nym Up
|
||||
|
||||
> Explore whether we're up through IsNymUp, a tool that helps check the heath of the Nym network as well as some mixnet related statistics!
|
||||
* [Deployed App](https://isnymup.com/)
|
||||
|
||||
|
||||
|
||||
|
||||
## <img src='../images/profile_picture/darkfi_over_nym_pp.png' style="float: right; width: 75px; height: 75px;">DarkFi over Nym
|
||||
|
||||
> DarkFi leverages Nym's mixnet as a pluggable transport for IRCD, their p2p IRC variant. Users can anonymously connect to peers over the network, ensuring secure and private communication within the DarkFi ecosystem.
|
||||
* [Github](https://github.com/darkrenaissance/darkfi)
|
||||
* [Documentation](https://darkrenaissance.github.io/darkfi/clients/nym_outbound.html)
|
||||
|
||||
|
||||
|
||||
|
||||
## <img src='../images/profile_picture/nymstr_email_pp.png' style="float: right; width: 75px; height: 75px;">Nymstr email
|
||||
|
||||
> Experience secure and private email communication with ease using Nymstr email, which enables seamless transmission of emails over a SOCKS5 proxy and our NYM mixnet!
|
||||
* [Github](https://github.com/dial0ut/nymstr-email)
|
||||
|
||||
|
||||
|
||||
|
||||
## <img src='../images/profile_picture/minibolt_pp.png' style="float: right; width: 75px; height: 75px;">Minibolt
|
||||
|
||||
> Anonymize your p2p inventory messages and mempool for your Bitcoin & Lightning full nodes on consumer PCs!
|
||||
* [Github](https://github.com/minibolt-guide/minibolt)
|
||||
* [Documentation](https://v2.minibolt.info/bonus-guides/system/nym-mixnet#proxying-bitcoin-core)
|
||||
|
||||
|
||||
|
||||
<br/> <br/>
|
||||
|
||||
# Community Guides
|
||||
|
||||
We aren't the only ones writing documentation: the Nym developer community is also a great source of guides and resources, some of which we've included here.
|
||||
|
||||
## <img src='../images/profile_picture/pastenym_ntv_pp.png' style="float: right; width: 75px; height: 75px;"> No Trust Verify
|
||||
|
||||
>No Trust Verify is a project that aims to build open-source, privacy-enhancing technologies that make it easier to use the Internet securely and anonymously. Their focus is on providing tools and services that make it simple for developers to create decentralized applications (dApps) that respect users' privacy.
|
||||
|
||||
* [Awesome Nym list](https://notrustverify.github.io/awesome-nym/) ([GitHub](https://github.com/notrustverify/awesome-nym))
|
||||
* A lot of guides can be found on the [NTV Blog](https://blog.notrustverify.ch/)
|
||||
|
||||
|
||||
## <img src='../images/profile_picture/pineappleproxy_pp.png' style="float: right; width: 75px; height: 75px;">The Way of the NYMJA
|
||||
|
||||
by Pineapple Proxy🍍
|
||||
|
||||
>Born out of a study group from Nym's Shipyard Academy, Pineapple Proxy has emerged as a cluster of motivated and skilled individuals who see the new internet taking shape. With vibecare at the heart of their approach, this zesty collective is on a mission to make privacy convenient for everyone via content, new tools, events, and novel experiences. They believe in collective intelligence, empathy, and collaboration as the means by which privacy will become a meaningful reality.
|
||||
* [Website](https://pnproxy.org/welcome.html) ([GitHub](https://github.com/Pineapple-Proxy-DAO/web))
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
# Community Applications
|
||||
|
||||
We love seeing our developer community create applications using Nym. If you would like to share your application with the community, please submit a pull request to the `main` branch of the `nymtech/dev-portal` [repository](https://github.com/nymtech/dev-portal).
|
||||
|
||||
<!--Pastenym *start-->
|
||||
|
||||
## <img src='../images/profile_picture/pastenym_ntv_pp.png' style="float: right; width: 75px; height: 75px;">Pastenym
|
||||
|
||||
>A [pastebin](https://pastebin.com) inspired project, offer a solution for sharing text with Nym products to offer full anonymity, even on metadata level.
|
||||
|
||||
* [Github](https://github.com/notrustverify/pastenym)
|
||||
* [Deployed Website App](https://pastenym.ch)
|
||||
|
||||
<!--Pastenym *end-->
|
||||
|
||||
<!--Pineapple *start-->
|
||||
|
||||
## <img src='../images/profile_picture/pineappleproxy_pp.png' style="float: right; width: 75px; height: 75px;">Nostr-Nym
|
||||
|
||||
> [Nostr-nym](https://github.com/notrustverify/nostr-nym) offer a solution to use [Nostr](https://nostr.how/) protocol by giving the possibility to run a relay on mixnet. By using a nostr client compatible with the mixnet, users can protect their privacy to be able to use Nostr has the want, without being observed.
|
||||
|
||||
* [Github](https://github.com/notrustverify/nostr-nym)
|
||||
* Deployed Website App coming soon
|
||||
|
||||
<!--Pineapple *end-->
|
||||
|
||||
|
||||
<!--Ethereum RPC Provider *start-->
|
||||
|
||||
## <img src='../images/profile_picture/ethereum_rpc_spook_pp.png' style="float: right; width: 75px; height: 75px;"> Spook
|
||||
|
||||
> Ethereum RPC request mixer uses the Nym network mixing service to anonymize RPC requests to the Ethereum network without revealing sensitive data and metadata.
|
||||
* [Github](https://github.com/EdenBlockVC/spook)
|
||||
|
||||
<!--Ethereum RPC Provider *end-->
|
||||
|
||||
<!--Ethereum Transaction Broadcaster *start-->
|
||||
|
||||
## <img src='../images/profile_picture/ethereum_transaction_broadcaster_root_pp.png' style="float: right; width: 75px; height: 75px;"> Ethereum Transaction Broadcaster
|
||||
|
||||
> Ethereum Transaction Broadcaster that uses the Nym Mixnet to provide privacy and anonymity for transactions on the Ethereum network command-line interface.
|
||||
|
||||
* [Github](https://github.com/noot/nym-ethtx)
|
||||
|
||||
<!--Ethereum Transaction Broadcaster *end-->
|
||||
|
||||
<!--NymDrive *start-->
|
||||
|
||||
## <img src='../images/profile_picture/nymdrive_saleel_pp.png' style="float: right; width: 75px; height: 75px;">NymDrive
|
||||
|
||||
> An open-source, decentralized, E2E encrypted, privacy friendly alternative to Google Drive/Dropbox, allowing for file encryption and decryption using the Nym Mixnet.
|
||||
* [Github](https://github.com/saleel/nymdrive)
|
||||
* [Demo](https://www.youtube.com/watch?v=5Rx73nw8NYI)
|
||||
* [Presentation](https://docs.google.com/presentation/d/1MpvIK32Mx9VKLVfMTcvbeyrsKHHUsTvDQ-3n31dR0NE/edit#slide=id.p)
|
||||
|
||||
<!--NymDrive *end-->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# Community Guides
|
||||
|
||||
We aren't the only ones writing documentation: the Nym developer community is also a great source of guides and resources, some of which we've included here.
|
||||
|
||||
## <img src='../images/profile_picture/pastenym_ntv_pp.png' style="float: right; width: 75px; height: 75px;"> No Trust Verify
|
||||
|
||||
>No Trust Verify is a project that aims to build open-source, privacy-enhancing technologies that make it easier to use the Internet securely and anonymously. Their focus is on providing tools and services that make it simple for developers to create decentralized applications (dApps) that respect users' privacy.
|
||||
|
||||
* [Awesome Nym list](https://notrustverify.github.io/awesome-nym/) ([GitHub](https://github.com/notrustverify/awesome-nym))
|
||||
* A lot of guides can be found on the [NTV Blog](https://blog.notrustverify.ch/)
|
||||
|
||||
## <img src='../images/profile_picture/pineappleproxy_pp.png' style="float: right; width: 75px; height: 75px;">The Way of the NYMJA
|
||||
|
||||
by Pineapple Proxy🍍
|
||||
|
||||
>Born out of a study group from Nym's Shipyard Academy, Pineapple Proxy has emerged as a cluster of motivated and skilled individuals who see the new internet taking shape. With vibecare at the heart of their approach, this zesty collective is on a mission to make privacy convenient for everyone via content, new tools, events, and novel experiences. They believe in collective intelligence, empathy, and collaboration as the means by which privacy will become a meaningful reality.
|
||||
* [Website](https://pnproxy.org/welcome.html) ([GitHub](https://github.com/Pineapple-Proxy-DAO/web))
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 314 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="351px" height="365px" viewBox="0 0 351 365" style="enable-background:new 0 0 351 365;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
</style>
|
||||
<g id="Layer_1_1_">
|
||||
</g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="175.5" y1="30%" x2="175.5" y2="99%">
|
||||
<stop offset="0" style="stop-color:#F05A28"/>
|
||||
<stop offset="1" style="stop-color:#FBCA0A"/>
|
||||
</linearGradient>
|
||||
<path class="st0" d="M342,161.2c-0.6-6.1-1.6-13.1-3.6-20.9c-2-7.7-5-16.2-9.4-25c-4.4-8.8-10.1-17.9-17.5-26.8
|
||||
c-2.9-3.5-6.1-6.9-9.5-10.2c5.1-20.3-6.2-37.9-6.2-37.9c-19.5-1.2-31.9,6.1-36.5,9.4c-0.8-0.3-1.5-0.7-2.3-1
|
||||
c-3.3-1.3-6.7-2.6-10.3-3.7c-3.5-1.1-7.1-2.1-10.8-3c-3.7-0.9-7.4-1.6-11.2-2.2c-0.7-0.1-1.3-0.2-2-0.3
|
||||
c-8.5-27.2-32.9-38.6-32.9-38.6c-27.3,17.3-32.4,41.5-32.4,41.5s-0.1,0.5-0.3,1.4c-1.5,0.4-3,0.9-4.5,1.3c-2.1,0.6-4.2,1.4-6.2,2.2
|
||||
c-2.1,0.8-4.1,1.6-6.2,2.5c-4.1,1.8-8.2,3.8-12.2,6c-3.9,2.2-7.7,4.6-11.4,7.1c-0.5-0.2-1-0.4-1-0.4c-37.8-14.4-71.3,2.9-71.3,2.9
|
||||
c-3.1,40.2,15.1,65.5,18.7,70.1c-0.9,2.5-1.7,5-2.5,7.5c-2.8,9.1-4.9,18.4-6.2,28.1c-0.2,1.4-0.4,2.8-0.5,4.2
|
||||
C18.8,192.7,8.5,228,8.5,228c29.1,33.5,63.1,35.6,63.1,35.6c0,0,0.1-0.1,0.1-0.1c4.3,7.7,9.3,15,14.9,21.9c2.4,2.9,4.8,5.6,7.4,8.3
|
||||
c-10.6,30.4,1.5,55.6,1.5,55.6c32.4,1.2,53.7-14.2,58.2-17.7c3.2,1.1,6.5,2.1,9.8,2.9c10,2.6,20.2,4.1,30.4,4.5
|
||||
c2.5,0.1,5.1,0.2,7.6,0.1l1.2,0l0.8,0l1.6,0l1.6-0.1l0,0.1c15.3,21.8,42.1,24.9,42.1,24.9c19.1-20.1,20.2-40.1,20.2-44.4l0,0
|
||||
c0,0,0-0.1,0-0.3c0-0.4,0-0.6,0-0.6l0,0c0-0.3,0-0.6,0-0.9c4-2.8,7.8-5.8,11.4-9.1c7.6-6.9,14.3-14.8,19.9-23.3
|
||||
c0.5-0.8,1-1.6,1.5-2.4c21.6,1.2,36.9-13.4,36.9-13.4c-3.6-22.5-16.4-33.5-19.1-35.6l0,0c0,0-0.1-0.1-0.3-0.2
|
||||
c-0.2-0.1-0.2-0.2-0.2-0.2c0,0,0,0,0,0c-0.1-0.1-0.3-0.2-0.5-0.3c0.1-1.4,0.2-2.7,0.3-4.1c0.2-2.4,0.2-4.9,0.2-7.3l0-1.8l0-0.9
|
||||
l0-0.5c0-0.6,0-0.4,0-0.6l-0.1-1.5l-0.1-2c0-0.7-0.1-1.3-0.2-1.9c-0.1-0.6-0.1-1.3-0.2-1.9l-0.2-1.9l-0.3-1.9
|
||||
c-0.4-2.5-0.8-4.9-1.4-7.4c-2.3-9.7-6.1-18.9-11-27.2c-5-8.3-11.2-15.6-18.3-21.8c-7-6.2-14.9-11.2-23.1-14.9
|
||||
c-8.3-3.7-16.9-6.1-25.5-7.2c-4.3-0.6-8.6-0.8-12.9-0.7l-1.6,0l-0.4,0c-0.1,0-0.6,0-0.5,0l-0.7,0l-1.6,0.1c-0.6,0-1.2,0.1-1.7,0.1
|
||||
c-2.2,0.2-4.4,0.5-6.5,0.9c-8.6,1.6-16.7,4.7-23.8,9c-7.1,4.3-13.3,9.6-18.3,15.6c-5,6-8.9,12.7-11.6,19.6c-2.7,6.9-4.2,14.1-4.6,21
|
||||
c-0.1,1.7-0.1,3.5-0.1,5.2c0,0.4,0,0.9,0,1.3l0.1,1.4c0.1,0.8,0.1,1.7,0.2,2.5c0.3,3.5,1,6.9,1.9,10.1c1.9,6.5,4.9,12.4,8.6,17.4
|
||||
c3.7,5,8.2,9.1,12.9,12.4c4.7,3.2,9.8,5.5,14.8,7c5,1.5,10,2.1,14.7,2.1c0.6,0,1.2,0,1.7,0c0.3,0,0.6,0,0.9,0c0.3,0,0.6,0,0.9-0.1
|
||||
c0.5,0,1-0.1,1.5-0.1c0.1,0,0.3,0,0.4-0.1l0.5-0.1c0.3,0,0.6-0.1,0.9-0.1c0.6-0.1,1.1-0.2,1.7-0.3c0.6-0.1,1.1-0.2,1.6-0.4
|
||||
c1.1-0.2,2.1-0.6,3.1-0.9c2-0.7,4-1.5,5.7-2.4c1.8-0.9,3.4-2,5-3c0.4-0.3,0.9-0.6,1.3-1c1.6-1.3,1.9-3.7,0.6-5.3
|
||||
c-1.1-1.4-3.1-1.8-4.7-0.9c-0.4,0.2-0.8,0.4-1.2,0.6c-1.4,0.7-2.8,1.3-4.3,1.8c-1.5,0.5-3.1,0.9-4.7,1.2c-0.8,0.1-1.6,0.2-2.5,0.3
|
||||
c-0.4,0-0.8,0.1-1.3,0.1c-0.4,0-0.9,0-1.2,0c-0.4,0-0.8,0-1.2,0c-0.5,0-1,0-1.5-0.1c0,0-0.3,0-0.1,0l-0.2,0l-0.3,0
|
||||
c-0.2,0-0.5,0-0.7-0.1c-0.5-0.1-0.9-0.1-1.4-0.2c-3.7-0.5-7.4-1.6-10.9-3.2c-3.6-1.6-7-3.8-10.1-6.6c-3.1-2.8-5.8-6.1-7.9-9.9
|
||||
c-2.1-3.8-3.6-8-4.3-12.4c-0.3-2.2-0.5-4.5-0.4-6.7c0-0.6,0.1-1.2,0.1-1.8c0,0.2,0-0.1,0-0.1l0-0.2l0-0.5c0-0.3,0.1-0.6,0.1-0.9
|
||||
c0.1-1.2,0.3-2.4,0.5-3.6c1.7-9.6,6.5-19,13.9-26.1c1.9-1.8,3.9-3.4,6-4.9c2.1-1.5,4.4-2.8,6.8-3.9c2.4-1.1,4.8-2,7.4-2.7
|
||||
c2.5-0.7,5.1-1.1,7.8-1.4c1.3-0.1,2.6-0.2,4-0.2c0.4,0,0.6,0,0.9,0l1.1,0l0.7,0c0.3,0,0,0,0.1,0l0.3,0l1.1,0.1
|
||||
c2.9,0.2,5.7,0.6,8.5,1.3c5.6,1.2,11.1,3.3,16.2,6.1c10.2,5.7,18.9,14.5,24.2,25.1c2.7,5.3,4.6,11,5.5,16.9c0.2,1.5,0.4,3,0.5,4.5
|
||||
l0.1,1.1l0.1,1.1c0,0.4,0,0.8,0,1.1c0,0.4,0,0.8,0,1.1l0,1l0,1.1c0,0.7-0.1,1.9-0.1,2.6c-0.1,1.6-0.3,3.3-0.5,4.9
|
||||
c-0.2,1.6-0.5,3.2-0.8,4.8c-0.3,1.6-0.7,3.2-1.1,4.7c-0.8,3.1-1.8,6.2-3,9.3c-2.4,6-5.6,11.8-9.4,17.1
|
||||
c-7.7,10.6-18.2,19.2-30.2,24.7c-6,2.7-12.3,4.7-18.8,5.7c-3.2,0.6-6.5,0.9-9.8,1l-0.6,0l-0.5,0l-1.1,0l-1.6,0l-0.8,0
|
||||
c0.4,0-0.1,0-0.1,0l-0.3,0c-1.8,0-3.5-0.1-5.3-0.3c-7-0.5-13.9-1.8-20.7-3.7c-6.7-1.9-13.2-4.6-19.4-7.8
|
||||
c-12.3-6.6-23.4-15.6-32-26.5c-4.3-5.4-8.1-11.3-11.2-17.4c-3.1-6.1-5.6-12.6-7.4-19.1c-1.8-6.6-2.9-13.3-3.4-20.1l-0.1-1.3l0-0.3
|
||||
l0-0.3l0-0.6l0-1.1l0-0.3l0-0.4l0-0.8l0-1.6l0-0.3c0,0,0,0.1,0-0.1l0-0.6c0-0.8,0-1.7,0-2.5c0.1-3.3,0.4-6.8,0.8-10.2
|
||||
c0.4-3.4,1-6.9,1.7-10.3c0.7-3.4,1.5-6.8,2.5-10.2c1.9-6.7,4.3-13.2,7.1-19.3c5.7-12.2,13.1-23.1,22-31.8c2.2-2.2,4.5-4.2,6.9-6.2
|
||||
c2.4-1.9,4.9-3.7,7.5-5.4c2.5-1.7,5.2-3.2,7.9-4.6c1.3-0.7,2.7-1.4,4.1-2c0.7-0.3,1.4-0.6,2.1-0.9c0.7-0.3,1.4-0.6,2.1-0.9
|
||||
c2.8-1.2,5.7-2.2,8.7-3.1c0.7-0.2,1.5-0.4,2.2-0.7c0.7-0.2,1.5-0.4,2.2-0.6c1.5-0.4,3-0.8,4.5-1.1c0.7-0.2,1.5-0.3,2.3-0.5
|
||||
c0.8-0.2,1.5-0.3,2.3-0.5c0.8-0.1,1.5-0.3,2.3-0.4l1.1-0.2l1.2-0.2c0.8-0.1,1.5-0.2,2.3-0.3c0.9-0.1,1.7-0.2,2.6-0.3
|
||||
c0.7-0.1,1.9-0.2,2.6-0.3c0.5-0.1,1.1-0.1,1.6-0.2l1.1-0.1l0.5-0.1l0.6,0c0.9-0.1,1.7-0.1,2.6-0.2l1.3-0.1c0,0,0.5,0,0.1,0l0.3,0
|
||||
l0.6,0c0.7,0,1.5-0.1,2.2-0.1c2.9-0.1,5.9-0.1,8.8,0c5.8,0.2,11.5,0.9,17,1.9c11.1,2.1,21.5,5.6,31,10.3
|
||||
c9.5,4.6,17.9,10.3,25.3,16.5c0.5,0.4,0.9,0.8,1.4,1.2c0.4,0.4,0.9,0.8,1.3,1.2c0.9,0.8,1.7,1.6,2.6,2.4c0.9,0.8,1.7,1.6,2.5,2.4
|
||||
c0.8,0.8,1.6,1.6,2.4,2.5c3.1,3.3,6,6.6,8.6,10c5.2,6.7,9.4,13.5,12.7,19.9c0.2,0.4,0.4,0.8,0.6,1.2c0.2,0.4,0.4,0.8,0.6,1.2
|
||||
c0.4,0.8,0.8,1.6,1.1,2.4c0.4,0.8,0.7,1.5,1.1,2.3c0.3,0.8,0.7,1.5,1,2.3c1.2,3,2.4,5.9,3.3,8.6c1.5,4.4,2.6,8.3,3.5,11.7
|
||||
c0.3,1.4,1.6,2.3,3,2.1c1.5-0.1,2.6-1.3,2.6-2.8C342.6,170.4,342.5,166.1,342,161.2z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.4 KiB |
@@ -36,7 +36,7 @@ In order to ensure uptime and reliability, it is recommended that you run some p
|
||||
|
||||
* If you're running a purely P2P application, then just integrating clients and having some method of sharing addresses should be enough to route your traffic through the mixnet.
|
||||
* If you're wanting to place the mixnet between your users' application instances and a server-based backend, you can use the [network requester](https://nymtech.net/docs/nodes/network-requester-setup.html) service provider binary to proxy these requests to your application backend, with the mixnet 'between' the user and your service, in order to prevent metadata leakage being broadcast to the internet.
|
||||
* If you're wanting to route RPC requests through the mixnet to a blockchain, you will need to look into setting up some sort of service that does the transaction broadcasting for you. You can find examples of such projects on the [community applications](../community-resources/community-applications.md) page.
|
||||
* If you're wanting to route RPC requests through the mixnet to a blockchain, you will need to look into setting up some sort of service that does the transaction broadcasting for you. You can find examples of such projects on the [community applications](../community-resources/community-applications-and-guides.md) page.
|
||||
|
||||
## Example application traffic flow
|
||||
### Initialization
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
There are multiple options to quickly connect to Nym and see the network in action without the need for any code changes to your application. At most, these involve running Nym as a second process alongside an existing application in order to send traffic through the mixnet.
|
||||
|
||||
Demo application:
|
||||
Demo applications:
|
||||
* a browser-based 'hello world' [chat application](https://chat-demo.nymtech.net). Either open in two browser windows and send messages to yourself, or share with a friend and send messages to each other through the mixnet!
|
||||
|
||||
* a Coconut-scheme based [Credential Library](https://coco-demo.nymtech.net/). This is a WASM implementation of our Coconut libraries which generate raw Coconut credentials. Test it to create and re-randomize your own credentials!
|
||||
<br>
|
||||
Proxy traffic with the Nym Socks5 client:
|
||||
* set up a plug-and-play connection with the [NymConnect](./nymconnect-gui.md) GUI for proxying Telegram, Electrum, Keybase or Blockstream Green traffic through the mixnet (~2 minutes).
|
||||
* [Download and run](./socks-proxy.md) the Nym Socks5 client via the CLI, for other desktop applications with SOCKS5 connection options (~30 minutes).
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# Matrix NymConnect Integration
|
||||
|
||||
|
||||
Chat applications became an essential part of human communication. Matrix chat has end to end encryption on protocol level and Element app users can sort their communication into spaces and rooms. Now the Matrix communities can rely on network privacy as NymConnect supports Matrix chat protocol.
|
||||
|
||||
Currently there is no option in Matrix's Element client to set a Socks5 proxy. In order to use Element via NymConnect users have to start it from the command-line. The setup is simple, for convenience a keyboard shortcut setting or terminal alias can be easily done.
|
||||
|
||||
|
||||
## Setup & Run
|
||||
|
||||
Make sure you have installed and started **[NymConnect](https://nymtech.net/developers/quickstart/nymconnect-gui.html)** on your desktop.
|
||||
|
||||
To then start Matrix's Element client via a Socks5 proxy connected to NymConnect, open terminal and run:
|
||||
|
||||
```sh
|
||||
element-desktop --proxy-server=socks5://127.0.0.1:1080
|
||||
```
|
||||
|
||||
## Optimise setup with a keybinding / alias
|
||||
|
||||
### Keybinding
|
||||
An eloquent solution to avoid entering a command every time is to setup your keybinding. Open your settings, navigate to `Keyboard Shortcuts` and choose to `Set Custom Shortcut`. `Name` and `Shortcut` fields are up to your preference, to the `Command` line add:
|
||||
|
||||
```sh
|
||||
element-desktop --proxy-server=socks5://127.0.0.1:1080
|
||||
```
|
||||
Make sure your `Shortcut` isn't already taken by something else in the menu.
|
||||
|
||||
An example can look like this.
|
||||
|
||||

|
||||
|
||||
Alternatively you can add a keybinding via the CLI, using whatever config files you edit for your given desktop environment / window manager.
|
||||
|
||||
### Create an alias
|
||||
If you prefer to simply shorten the length of the command (or all your keybindings are already taken) then you can simply create an alias for this long-winded command (this example aliases that command to the single word `element`, but you can replace it with whatever you like):
|
||||
|
||||
**Linux**
|
||||
|
||||
```sh
|
||||
alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080"
|
||||
```
|
||||
|
||||
To make this alias persist, then add this to your `.bashrc` or `.zshrc` file (usually located in your `$HOME` directory) and `source` that file. This can be done by appending the alias command directly to the shell config file with one command.
|
||||
|
||||
For `bash` enter:
|
||||
|
||||
```sh
|
||||
alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080" >> ~/.bashrc
|
||||
```
|
||||
|
||||
For `zsh` enter:
|
||||
|
||||
```sh
|
||||
alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080" >> ~/.zshrc
|
||||
```
|
||||
|
||||
You can add the alias manually by opening your `$HOME` directory, enable hidden files (press `ctrl` + `h`) and open `.bashrc` or `.zshrc` file (based on your terminal setup) in a text editor, paste the string `alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080"` to the the end, save and exit. Start a new terminal and run `element`.
|
||||
|
||||
**Mac**
|
||||
|
||||
```sh
|
||||
alias element="open -a Element --args --proxy-server=socks5://127.0.0.1:1080"
|
||||
|
||||
```
|
||||
|
||||
To make this alias persist, then add this to your `.zshrc` (or `.bashrc`/`.profile`) file (usually located in your `$HOME` directory) and `source` that file. This can be done by appending the alias command directly to the shell config file with one command.
|
||||
|
||||
For `zsh` enter:
|
||||
|
||||
```sh
|
||||
alias element="open -a Element --args --proxy-server=socks5://127.0.0.1:1080" >> ~/.zshrc
|
||||
```
|
||||
|
||||
For `.bashrc` or `.profile` just change the end of the command.
|
||||
|
||||
You can add the alias manually by opening your `$HOME` directory, enable hidden files (in Finder press `Shift` + `Command` + `.`) and open `.zshrc` file (or `.bashrc`/`.profile`) in a text editor, paste the string `alias element="open -a Element --args --proxy-server=socks5://127.0.0.1:1080"` to the the end, save and exit. Start a new terminal and run `element`.
|
||||
|
||||
|
||||
**Now you can run Element through the Nym Mixnet with a single-word command.**
|
||||
@@ -0,0 +1,42 @@
|
||||
# Monero NymConnect Integration
|
||||
|
||||
*New Nym mixnet integration launched for Monero desktop to secure the right to financial privacy and censorship-resistance*
|
||||
|
||||

|
||||
|
||||
Financial privacy is an important component of digital currencies and the use of Nym will provide users with the highest level of privacy at the infrastructure level. All users of digital currencies should be afforded equal rights to protection from financial surveillance.
|
||||
|
||||
A team made up of Monero community members have successfully set up a service provider to use Monero (using the Monero desktop wallet) over the Nym mixnet. This allows Monero users to easily use NymConnect to run Monero over the mixnet, thereby enhancing the privacy of Monero transactions.
|
||||
|
||||
## How can I use Monero over the Nym mixnet?
|
||||
|
||||
The mainnet service provider to Monero over the Nym mixnet is now ready for use via [NymConnect](https://nymtech.net/download-nymconnect/).
|
||||
|
||||
* Download and open the latest version of [NymConnect](https://nymtech.net/download-nymconnect/).
|
||||
* Click on the top left options and go to Settings
|
||||
* Go to “Select service provider” and turn it on
|
||||
* For Mainnet, search for this provider or insert it manually:
|
||||
|
||||
```sh
|
||||
i1TiuoNp4jp9weffCW7tPnkb4hRTPydRjX8iXFVaYDG.88Z1hruuvbzWpdCE2xYnTbPNrr49j4s7mmUQC5wvRRLZ@3EPuxwGn2WP2HdxybzoDa5QsohYSP76aQQRUJuPMvk23
|
||||
```
|
||||
|
||||
* Go to the main NymConnect interface and connect to the mixnet
|
||||
|
||||
Then go to your Monero wallet (gui or otherwise) and change the settings to run over socks5 proxy:
|
||||
|
||||
**Monero desktop:**
|
||||
|
||||
* Settings -> Interface -> Socks5 proxy -> Add values: IP address `localhost`, Port `1080`
|
||||
|
||||
<iframe width="700" height="400" src="https://www.youtube.com/embed/oSHnk1BG_f0" title="Demo: Connect Your Monero Wallet to the Nym Mixnet via NymConnect" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
|
||||
**CLI**
|
||||
|
||||
* **Monerod:** add `--proxy 127.0.0.1:1080 --bootstrap-daemon-proxy 127.0.0.1:1080` to args
|
||||
|
||||
* **Monero-wallet-{rpc, cli}:** add `--proxy 127.0.0.1:1080 --daemon-ssl-allow-any-cert` to args
|
||||
|
||||
Follow the instructions and the Monero mainnet will be connected through to the Nym mixnet.
|
||||
|
||||
For those who want to try it out in testnet, a stagenet service provider is also available: [https://nymtech.net/.wellknown/connect/service-providers.json](https://nymtech.net/.wellknown/connect/service-providers.json)
|
||||
@@ -12,7 +12,7 @@ Simply fill in the fields in your browser and click `Send`. In your browser you
|
||||
|
||||
<img src="../../images/tutorial_image_5.png"/>
|
||||
|
||||
This small project can be used as a template to start conceptualizing and developing more complex PEApps. Stay tuned for more soon, and if you're searching for inspiration check out the [community apps](../../community-resources/community-applications.md) list!
|
||||
This small project can be used as a template to start conceptualizing and developing more complex PEApps. Stay tuned for more soon, and if you're searching for inspiration check out the [community apps](../../community-resources/community-applications-and-guides.md) list!
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -62,7 +62,8 @@ h3:target::before,
|
||||
h4:target::before,
|
||||
h5:target::before,
|
||||
h6:target::before {
|
||||
display: inline-block;
|
||||
/* display "none" in order to avoid default artifacts on the community-applications-and-guides page */
|
||||
display: none;
|
||||
content: "»";
|
||||
margin-left: -30px;
|
||||
width: 30px;
|
||||
|
||||
@@ -48,9 +48,9 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install`
|
||||
# https://gitlab.com/tglman/mdbook-variables/
|
||||
[preprocessor.variables.variables]
|
||||
minimum_rust_version = "1.66"
|
||||
|
||||
# old variables - this is still needed for links.. TODO change to develop?
|
||||
platform_release_version = "v1.1.21"
|
||||
# vars for links: TODO think on how to streamline updating
|
||||
platform_release_version = "v1.1.22"
|
||||
wallet_release_version = "v1.2.5"
|
||||
|
||||
[preprocessor.last-changed]
|
||||
command = "mdbook-last-changed"
|
||||
@@ -87,7 +87,7 @@ copy-fonts = true
|
||||
no-section-label = false
|
||||
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"]
|
||||
additional-js = ["theme/pagetoc.js"]
|
||||
git-repository-url = "https://github.com/nymtech/docs"
|
||||
git-repository-url = "https://github.com/nymtech/nym"
|
||||
git-repository-icon = "fa-github"
|
||||
# edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}"
|
||||
# site-url = "/docs/"
|
||||
|
||||
@@ -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
|
||||
@@ -102,4 +102,4 @@ The following code shows how you can use the SDK to create and use a [credential
|
||||
{{#include ../../../../sdk/rust/nym-sdk/examples/bandwidth.rs}}
|
||||
```
|
||||
|
||||
You can read more about Coconut credentials (also referred to as `zk-Nym`) [here](../cococnut.md).
|
||||
You can read more about Coconut credentials (also referred to as `zk-Nym`) [here](../coconut.md).
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
16
|
||||
18
|
||||
|
||||
+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
|
||||
}
|
||||
|
||||
+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
|
||||
@@ -2,16 +2,18 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.1.14] (2023-06-27)
|
||||
## [v1.1.14] (2023-07-04)
|
||||
|
||||
- Nym connect fails to start when encountering an old config version ([#3588])
|
||||
- NC desktop - apps section adjustments + add monero integration ([#2977])
|
||||
- nym-connect: use different service provider directory when medium toggle enabled ([#3617])
|
||||
- Fix medium toggle in nym-connect ([#3590])
|
||||
- [bugfix] NC: load old gateway configuration if we're not registering ([#3586])
|
||||
- nym-connect: medium speed setting ([#3585])
|
||||
|
||||
[#3588]: https://github.com/nymtech/nym/issues/3588
|
||||
[#2977]: https://github.com/nymtech/nym/issues/2977
|
||||
[#3617]: https://github.com/nymtech/nym/pull/3617
|
||||
[#3590]: https://github.com/nymtech/nym/pull/3590
|
||||
[#3586]: https://github.com/nymtech/nym/pull/3586
|
||||
[#3585]: https://github.com/nymtech/nym/pull/3585
|
||||
|
||||
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]]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user