Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 77d7fede76 | |||
| f6929e365b | |||
| f98911f904 | |||
| c1be720e49 | |||
| b4a719dbab | |||
| ce99ccea44 | |||
| 595a76ee50 | |||
| dda7c09ec8 | |||
| c27713c678 | |||
| b8125d735e | |||
| 96617469e9 | |||
| 10ade80da0 | |||
| 6c8d5c129d | |||
| 4c01ee0150 | |||
| 9c85d51e34 | |||
| 30dc257ba7 | |||
| 1878720a31 | |||
| ae0d9f3179 | |||
| 1688eb9477 | |||
| 3c1939953c | |||
| 7de43540b9 | |||
| 979244f9da | |||
| 9e555ebd8a | |||
| 579ed7bb6e | |||
| 1655933678 | |||
| cd2978a8b0 | |||
| 6fcdbc15ce | |||
| ceee2d4466 | |||
| 8ee3ec2f4e | |||
| 3ad3837c87 |
@@ -10,57 +10,61 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04-16-core
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
continue-on-error: true
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Build
|
||||
run: yarn && yarn build && yarn build:ci:storybook
|
||||
- name: Deploy branch to CI www (storybook)
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "ts-packages/dist/storybook/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Deploy branch to CI www (example)
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "ts-packages/dist/example/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}-example
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: ts-packages
|
||||
NYM_PROJECT_NAME: "ts-packages"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
continue-on-error: true
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
run_install: true
|
||||
|
||||
- name: Build
|
||||
run: pnpm i && pnpm run build && pnpm run build:ci:storybook
|
||||
- name: Deploy branch to CI www (storybook)
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "ts-packages/dist/storybook/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Deploy branch to CI www (example)
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "ts-packages/dist/example/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}-example
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: ts-packages
|
||||
NYM_PROJECT_NAME: "ts-packages"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
|
||||
@@ -21,8 +21,12 @@ jobs:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
run_install: true
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -35,23 +39,20 @@ jobs:
|
||||
- name: Install wasm-opt
|
||||
uses: ./.github/actions/install-wasm-opt
|
||||
with:
|
||||
version: '116'
|
||||
version: "116"
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.20'
|
||||
|
||||
- name: Install
|
||||
run: yarn
|
||||
go-version: "1.20"
|
||||
|
||||
- name: Build packages
|
||||
run: yarn build:ci
|
||||
run: pnpm run build:ci
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
run: pnpm run lint
|
||||
- name: Typecheck with tsc
|
||||
run: yarn tsc
|
||||
run: pnpm run tsc
|
||||
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
|
||||
@@ -4,7 +4,7 @@ on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- 'explorer/**'
|
||||
- "explorer/**"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -14,78 +14,82 @@ jobs:
|
||||
build:
|
||||
runs-on: custom-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
continue-on-error: true
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
continue-on-error: true
|
||||
- name: Build shared packages
|
||||
run: cd .. && yarn && yarn build
|
||||
- name: Set environment from the example
|
||||
run: cp .env.prod .env
|
||||
# - run: yarn test
|
||||
# continue-on-error: true
|
||||
- run: yarn && yarn build
|
||||
continue-on-error: true
|
||||
- run: yarn storybook:build
|
||||
name: Build storybook
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "explorer/dist/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/network-explorer-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Deploy storybook to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "explorer/storybook-static/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ne-sb-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: network-explorer
|
||||
NYM_PROJECT_NAME: "Network Explorer"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "network-explorer-${{ env.GITHUB_REF_SLUG }}"
|
||||
NYM_CI_WWW_LOCATION_STORYBOOK: "ne-sb-${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
- name: Deploy
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CD_PROD_NE_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "explorer/dist/"
|
||||
REMOTE_HOST: ${{ secrets.CD_PROD_NE_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CD_PROD_NE_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CD_PROD_NE_REMOTE_TARGET }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
continue-on-error: true
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
continue-on-error: true
|
||||
- name: Build shared packages
|
||||
run: cd .. && yarn && yarn build
|
||||
- name: Set environment from the example
|
||||
run: cp .env.prod .env
|
||||
# - run: yarn test
|
||||
# continue-on-error: true
|
||||
- run: yarn && yarn build
|
||||
continue-on-error: true
|
||||
- run: yarn storybook:build
|
||||
name: Build storybook
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "explorer/dist/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/network-explorer-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Deploy storybook to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "explorer/storybook-static/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ne-sb-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: network-explorer
|
||||
NYM_PROJECT_NAME: "Network Explorer"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "network-explorer-${{ env.GITHUB_REF_SLUG }}"
|
||||
NYM_CI_WWW_LOCATION_STORYBOOK: "ne-sb-${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
- name: Deploy
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CD_PROD_NE_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "explorer/dist/"
|
||||
REMOTE_HOST: ${{ secrets.CD_PROD_NE_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CD_PROD_NE_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CD_PROD_NE_REMOTE_TARGET }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
|
||||
@@ -3,72 +3,75 @@ name: ci-nym-wallet-storybook
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'nym-wallet/**'
|
||||
- "nym-wallet/**"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
continue-on-error: true
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
continue-on-error: true
|
||||
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
run_install: true
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- 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 wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
|
||||
- name: Build dependencies
|
||||
run: yarn && yarn build
|
||||
- name: Build dependencies
|
||||
run: pnpm build
|
||||
|
||||
- name: Build storybook
|
||||
run: yarn storybook:build
|
||||
working-directory: ./nym-wallet
|
||||
- name: Build storybook
|
||||
run: pnpm run storybook:build
|
||||
working-directory: ./wallet
|
||||
|
||||
- name: Deploy branch to CI www (storybook)
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "nym-wallet/storybook-static/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/wallet-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Deploy branch to CI www (storybook)
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "nym-wallet/storybook-static/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/wallet-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: nym-wallet
|
||||
NYM_PROJECT_NAME: "nym-wallet"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "wallet-${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: nym-wallet
|
||||
NYM_PROJECT_NAME: "nym-wallet"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "wallet-${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
|
||||
@@ -17,18 +17,23 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.17
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
run_install: true
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.20'
|
||||
go-version: "1.20"
|
||||
|
||||
- name: Install wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
@@ -36,16 +41,15 @@ jobs:
|
||||
- name: Install wasm-opt
|
||||
uses: ./.github/actions/install-wasm-opt
|
||||
with:
|
||||
version: '116'
|
||||
version: "116"
|
||||
|
||||
- name: Build branch WASM packages
|
||||
run: make sdk-wasm-build
|
||||
|
||||
- name: Install
|
||||
run: yarn
|
||||
- name: Build
|
||||
run: yarn docs:prod:build
|
||||
- name: Deploy branch to CI www (docs)
|
||||
run: pnpm docs:prod:build
|
||||
|
||||
- name: Deploy branch to CI www (docs)
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
@@ -57,7 +61,7 @@ jobs:
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/sdk-ts-docs-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
run: pnpm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
@@ -75,4 +79,4 @@ jobs:
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
@@ -61,12 +61,12 @@ jobs:
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
fileName: ".env"
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
run: cd .. && pnpm i --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies and build it
|
||||
env:
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
run: yarn && yarn build
|
||||
run: pnpm i && pnpm build
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
|
||||
Generated
+7
-7
@@ -2221,7 +2221,7 @@ dependencies = [
|
||||
"atomic 0.6.0",
|
||||
"pear",
|
||||
"serde",
|
||||
"toml 0.8.14",
|
||||
"toml 0.8.15",
|
||||
"uncased",
|
||||
"version_check",
|
||||
]
|
||||
@@ -5037,7 +5037,7 @@ dependencies = [
|
||||
"sysinfo 0.30.12",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"toml 0.8.14",
|
||||
"toml 0.8.15",
|
||||
"tracing",
|
||||
"url",
|
||||
"zeroize",
|
||||
@@ -8626,14 +8626,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.14"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
|
||||
checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit 0.22.14",
|
||||
"toml_edit 0.22.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8660,9 +8660,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.14"
|
||||
version = "0.22.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
|
||||
checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788"
|
||||
dependencies = [
|
||||
"indexmap 2.2.6",
|
||||
"serde",
|
||||
|
||||
@@ -107,12 +107,12 @@ sdk-wasm-build:
|
||||
$(MAKE) -C wasm/zknym-lib
|
||||
#$(MAKE) -C wasm/full-nym-wasm
|
||||
|
||||
# run this from npm/yarn to ensure tools are in the path, e.g. yarn build:sdk from root of repo
|
||||
# run this from npm/pnpm to ensure tools are in the path, e.g. pnpm build:sdk from root of repo
|
||||
sdk-typescript-build:
|
||||
npx lerna run --scope @nymproject/sdk build --stream
|
||||
npx lerna run --scope @nymproject/mix-fetch build --stream
|
||||
npx lerna run --scope @nymproject/node-tester build --stream
|
||||
yarn --cwd sdk/typescript/codegen/contract-clients build
|
||||
pnpm run --filter @nymproject/sdk --stream build
|
||||
pnpm run --filter @nymproject/mix-fetch --stream build
|
||||
pnpm run --filter @nymproject/node-tester --stream build
|
||||
pnpm --cwd sdk/typescript/codegen/contract-clients build
|
||||
|
||||
# NOTE: These targets are part of the main workspace (but not as wasm32-unknown-unknown)
|
||||
WASM_CRATES = extension-storage nym-client-wasm nym-node-tester-wasm zknym-lib
|
||||
@@ -170,10 +170,10 @@ build-nym-mixnode:
|
||||
|
||||
generate-typescript:
|
||||
cd tools/ts-rs-cli && cargo run && cd ../..
|
||||
yarn types:lint:fix
|
||||
pnpm types:lint:fix
|
||||
|
||||
run-api-tests:
|
||||
cd nym-api/tests/functional_test && yarn test:qa
|
||||
cd nym-api/tests/functional_test && pnpm test:qa
|
||||
|
||||
# Build debian package, and update PPA
|
||||
deb-mixnode: build-nym-mixnode
|
||||
|
||||
@@ -1,26 +1,15 @@
|
||||
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::Parser;
|
||||
use cosmwasm_std::Decimal;
|
||||
use log::{debug, info};
|
||||
use nym_mixnet_contract_common::{
|
||||
InitialRewardingParams, InstantiateMsg, OperatingCostRange, Percent, ProfitMarginRange,
|
||||
};
|
||||
use nym_network_defaults::mainnet::MIX_DENOM;
|
||||
use nym_network_defaults::TOTAL_SUPPLY;
|
||||
use nym_validator_client::nyxd::{AccountId, Coin};
|
||||
|
||||
use cosmwasm_std::Decimal;
|
||||
use nym_mixnet_contract_common::{InitialRewardingParams, InstantiateMsg, Percent};
|
||||
use nym_validator_client::nyxd::AccountId;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
pub fn default_maximum_operating_cost() -> Coin {
|
||||
Coin::new(TOTAL_SUPPLY, MIX_DENOM.base)
|
||||
}
|
||||
|
||||
pub fn default_minimum_operating_cost() -> Coin {
|
||||
Coin::new(0, MIX_DENOM.base)
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[clap(long)]
|
||||
@@ -61,18 +50,6 @@ pub struct Args {
|
||||
|
||||
#[clap(long, default_value_t = 240)]
|
||||
pub active_set_size: u32,
|
||||
|
||||
#[clap(long, default_value_t = Percent::zero())]
|
||||
pub minimum_profit_margin_percent: Percent,
|
||||
|
||||
#[clap(long, default_value_t = Percent::hundred())]
|
||||
pub maximum_profit_margin_percent: Percent,
|
||||
|
||||
#[clap(long, default_value_t = default_minimum_operating_cost())]
|
||||
pub minimum_interval_operating_cost: Coin,
|
||||
|
||||
#[clap(long, default_value_t = default_maximum_operating_cost())]
|
||||
pub maximum_interval_operating_cost: Coin,
|
||||
}
|
||||
|
||||
pub async fn generate(args: Args) {
|
||||
@@ -120,10 +97,6 @@ pub async fn generate(args: Args) {
|
||||
.expect("Rewarding (mix) denom has to be set")
|
||||
});
|
||||
|
||||
if args.minimum_interval_operating_cost.denom != args.maximum_interval_operating_cost.denom {
|
||||
panic!("different denoms for operating cost bounds")
|
||||
}
|
||||
|
||||
let instantiate_msg = InstantiateMsg {
|
||||
rewarding_validator_address: rewarding_validator_address.to_string(),
|
||||
vesting_contract_address: vesting_contract_address.to_string(),
|
||||
@@ -131,14 +104,6 @@ pub async fn generate(args: Args) {
|
||||
epochs_in_interval: args.epochs_in_interval,
|
||||
epoch_duration: Duration::from_secs(args.epoch_duration),
|
||||
initial_rewarding_params,
|
||||
profit_margin: ProfitMarginRange {
|
||||
minimum: args.minimum_profit_margin_percent,
|
||||
maximum: args.maximum_profit_margin_percent,
|
||||
},
|
||||
interval_operating_cost: OperatingCostRange {
|
||||
minimum: args.minimum_interval_operating_cost.amount.into(),
|
||||
maximum: args.maximum_interval_operating_cost.amount.into(),
|
||||
},
|
||||
};
|
||||
|
||||
debug!("instantiate_msg: {:?}", instantiate_msg);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{EpochEventId, EpochState, IdentityKey, MixId, OperatingCostRange, ProfitMarginRange};
|
||||
use crate::{EpochEventId, EpochState, IdentityKey, MixId};
|
||||
use contracts_common::signing::verifier::ApiVerifierError;
|
||||
use contracts_common::Percent;
|
||||
use cosmwasm_std::{Addr, Coin, Decimal, Uint128};
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -240,19 +239,6 @@ pub enum MixnetContractError {
|
||||
#[from]
|
||||
source: ApiVerifierError,
|
||||
},
|
||||
|
||||
#[error("the provided profit margin ({provided}) is outside the allowed range: {range}")]
|
||||
ProfitMarginOutsideRange {
|
||||
provided: Percent,
|
||||
range: ProfitMarginRange,
|
||||
},
|
||||
|
||||
#[error("the provided interval operating cost ({provided}{denom}) is outside the allowed range: {range}")]
|
||||
OperatingCostOutsideRange {
|
||||
denom: String,
|
||||
provided: Uint128,
|
||||
range: OperatingCostRange,
|
||||
},
|
||||
}
|
||||
|
||||
impl MixnetContractError {
|
||||
|
||||
@@ -10,10 +10,7 @@ use crate::helpers::IntoBaseDecimal;
|
||||
use crate::reward_params::{NodeRewardParams, RewardingParams};
|
||||
use crate::rewarding::helpers::truncate_reward;
|
||||
use crate::rewarding::RewardDistribution;
|
||||
use crate::{
|
||||
Delegation, EpochEventId, EpochId, IdentityKey, MixId, OperatingCostRange, Percent,
|
||||
ProfitMarginRange, SphinxKey,
|
||||
};
|
||||
use crate::{Delegation, EpochEventId, EpochId, IdentityKey, MixId, Percent, SphinxKey};
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{Addr, Coin, Decimal, StdResult, Uint128};
|
||||
use schemars::JsonSchema;
|
||||
@@ -155,16 +152,6 @@ impl MixNodeRewarding {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn normalise_profit_margin(&mut self, allowed_range: ProfitMarginRange) {
|
||||
self.cost_params.profit_margin_percent =
|
||||
allowed_range.normalise(self.cost_params.profit_margin_percent)
|
||||
}
|
||||
|
||||
pub fn normalise_operating_cost(&mut self, allowed_range: OperatingCostRange) {
|
||||
self.cost_params.interval_operating_cost.amount =
|
||||
allowed_range.normalise(self.cost_params.interval_operating_cost.amount)
|
||||
}
|
||||
|
||||
/// Determines whether this node is still bonded. This is performed via a simple check,
|
||||
/// if there are no tokens left associated with the operator, it means they have unbonded
|
||||
/// and those params only exist for the purposes of calculating rewards for delegators that
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::delegation::{self, OwnerProxySubKey};
|
||||
@@ -12,7 +12,6 @@ use crate::reward_params::{
|
||||
IntervalRewardParams, IntervalRewardingParamsUpdate, Performance, RewardingParams,
|
||||
};
|
||||
use crate::types::{ContractStateParams, LayerAssignment, MixId};
|
||||
use crate::{OperatingCostRange, ProfitMarginRange};
|
||||
use contracts_common::{signing::MessageSignature, IdentityKey, Percent};
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{Coin, Decimal};
|
||||
@@ -58,12 +57,6 @@ pub struct InstantiateMsg {
|
||||
pub epochs_in_interval: u32,
|
||||
pub epoch_duration: Duration,
|
||||
pub initial_rewarding_params: InitialRewardingParams,
|
||||
|
||||
#[serde(default)]
|
||||
pub profit_margin: ProfitMarginRange,
|
||||
|
||||
#[serde(default)]
|
||||
pub interval_operating_cost: OperatingCostRange,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
|
||||
use crate::error::MixnetContractError;
|
||||
use crate::Layer;
|
||||
use contracts_common::Percent;
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::Addr;
|
||||
use cosmwasm_std::Coin;
|
||||
use cosmwasm_std::{Addr, Uint128};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Index;
|
||||
|
||||
// type aliases for better reasoning about available data
|
||||
@@ -17,65 +15,6 @@ pub type SphinxKeyRef<'a> = &'a str;
|
||||
pub type MixId = u32;
|
||||
pub type BlockHeight = u64;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RangedValue<T> {
|
||||
pub minimum: T,
|
||||
pub maximum: T,
|
||||
}
|
||||
|
||||
impl<T> Copy for RangedValue<T> where T: Copy {}
|
||||
|
||||
pub type ProfitMarginRange = RangedValue<Percent>;
|
||||
pub type OperatingCostRange = RangedValue<Uint128>;
|
||||
|
||||
impl<T> Display for RangedValue<T>
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} - {}", self.minimum, self.maximum)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ProfitMarginRange {
|
||||
fn default() -> Self {
|
||||
ProfitMarginRange {
|
||||
minimum: Percent::zero(),
|
||||
maximum: Percent::hundred(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OperatingCostRange {
|
||||
fn default() -> Self {
|
||||
OperatingCostRange {
|
||||
minimum: Uint128::zero(),
|
||||
|
||||
// 1 billion (native tokens, i.e. 1 billion * 1'000'000 base tokens) - the total supply
|
||||
maximum: Uint128::new(1_000_000_000_000_000),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RangedValue<T>
|
||||
where
|
||||
T: Copy + PartialOrd + PartialEq,
|
||||
{
|
||||
pub fn normalise(&self, value: T) -> T {
|
||||
if value < self.minimum {
|
||||
self.minimum
|
||||
} else if value > self.maximum {
|
||||
self.maximum
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
pub fn within_range(&self, value: T) -> bool {
|
||||
value >= self.minimum && value <= self.maximum
|
||||
}
|
||||
}
|
||||
|
||||
/// Specifies layer assignment for the given mixnode.
|
||||
#[cw_serde]
|
||||
pub struct LayerAssignment {
|
||||
@@ -215,14 +154,4 @@ pub struct ContractStateParams {
|
||||
|
||||
/// Minimum amount a gateway must pledge to get into the system.
|
||||
pub minimum_gateway_pledge: Coin,
|
||||
|
||||
/// Defines the allowed profit margin range of operators.
|
||||
/// default: 0% - 100%
|
||||
#[serde(default)]
|
||||
pub profit_margin: ProfitMarginRange,
|
||||
|
||||
/// Defines the allowed interval operating cost range of operators.
|
||||
/// default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)
|
||||
#[serde(default)]
|
||||
pub interval_operating_cost: OperatingCostRange,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use nym_mixnet_contract_common::ContractsCommonError;
|
||||
use nym_validator_client::error::TendermintRpcError;
|
||||
use nym_validator_client::nym_api::error::NymAPIError;
|
||||
use nym_validator_client::{nyxd::error::NyxdError, ValidatorClientError};
|
||||
@@ -9,9 +8,6 @@ use thiserror::Error;
|
||||
// TODO: ask @MS why this even exists
|
||||
#[derive(Error, Debug)]
|
||||
pub enum TypesError {
|
||||
#[error(transparent)]
|
||||
ContractsCommon(#[from] ContractsCommonError),
|
||||
|
||||
#[error("{source}")]
|
||||
NyxdError {
|
||||
#[from]
|
||||
|
||||
@@ -24,7 +24,5 @@ pub fn default_mixnet_init_msg() -> nym_mixnet_contract_common::InstantiateMsg {
|
||||
rewarded_set_size: 240,
|
||||
active_set_size: 100,
|
||||
},
|
||||
profit_margin: Default::default(),
|
||||
interval_operating_cost: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,28 +26,6 @@
|
||||
"initial_rewarding_params": {
|
||||
"$ref": "#/definitions/InitialRewardingParams"
|
||||
},
|
||||
"interval_operating_cost": {
|
||||
"default": {
|
||||
"maximum": "1000000000000000",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Uint128"
|
||||
}
|
||||
]
|
||||
},
|
||||
"profit_margin": {
|
||||
"default": {
|
||||
"maximum": "1",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Percent"
|
||||
}
|
||||
]
|
||||
},
|
||||
"rewarding_denom": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -134,42 +112,6 @@
|
||||
"$ref": "#/definitions/Decimal"
|
||||
}
|
||||
]
|
||||
},
|
||||
"RangedValue_for_Percent": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RangedValue_for_Uint128": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Uint128": {
|
||||
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1230,18 +1172,6 @@
|
||||
"minimum_mixnode_pledge"
|
||||
],
|
||||
"properties": {
|
||||
"interval_operating_cost": {
|
||||
"description": "Defines the allowed interval operating cost range of operators. default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)",
|
||||
"default": {
|
||||
"maximum": "1000000000000000",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Uint128"
|
||||
}
|
||||
]
|
||||
},
|
||||
"minimum_gateway_pledge": {
|
||||
"description": "Minimum amount a gateway must pledge to get into the system.",
|
||||
"allOf": [
|
||||
@@ -1268,18 +1198,6 @@
|
||||
"$ref": "#/definitions/Coin"
|
||||
}
|
||||
]
|
||||
},
|
||||
"profit_margin": {
|
||||
"description": "Defines the allowed profit margin range of operators. default: 0% - 100%",
|
||||
"default": {
|
||||
"maximum": "1",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Percent"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -1614,38 +1532,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"RangedValue_for_Percent": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RangedValue_for_Uint128": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Uint128": {
|
||||
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
|
||||
"type": "string"
|
||||
@@ -8177,18 +8063,6 @@
|
||||
"minimum_mixnode_pledge"
|
||||
],
|
||||
"properties": {
|
||||
"interval_operating_cost": {
|
||||
"description": "Defines the allowed interval operating cost range of operators. default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)",
|
||||
"default": {
|
||||
"maximum": "1000000000000000",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Uint128"
|
||||
}
|
||||
]
|
||||
},
|
||||
"minimum_gateway_pledge": {
|
||||
"description": "Minimum amount a gateway must pledge to get into the system.",
|
||||
"allOf": [
|
||||
@@ -8215,62 +8089,6 @@
|
||||
"$ref": "#/definitions/Coin"
|
||||
}
|
||||
]
|
||||
},
|
||||
"profit_margin": {
|
||||
"description": "Defines the allowed profit margin range of operators. default: 0% - 100%",
|
||||
"default": {
|
||||
"maximum": "1",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Percent"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Decimal": {
|
||||
"description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)",
|
||||
"type": "string"
|
||||
},
|
||||
"Percent": {
|
||||
"description": "Percent represents a value between 0 and 100% (i.e. between 0.0 and 1.0)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Decimal"
|
||||
}
|
||||
]
|
||||
},
|
||||
"RangedValue_for_Percent": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RangedValue_for_Uint128": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -8291,18 +8109,6 @@
|
||||
"minimum_mixnode_pledge"
|
||||
],
|
||||
"properties": {
|
||||
"interval_operating_cost": {
|
||||
"description": "Defines the allowed interval operating cost range of operators. default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)",
|
||||
"default": {
|
||||
"maximum": "1000000000000000",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Uint128"
|
||||
}
|
||||
]
|
||||
},
|
||||
"minimum_gateway_pledge": {
|
||||
"description": "Minimum amount a gateway must pledge to get into the system.",
|
||||
"allOf": [
|
||||
@@ -8329,18 +8135,6 @@
|
||||
"$ref": "#/definitions/Coin"
|
||||
}
|
||||
]
|
||||
},
|
||||
"profit_margin": {
|
||||
"description": "Defines the allowed profit margin range of operators. default: 0% - 100%",
|
||||
"default": {
|
||||
"maximum": "1",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Percent"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@@ -8360,50 +8154,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Decimal": {
|
||||
"description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)",
|
||||
"type": "string"
|
||||
},
|
||||
"Percent": {
|
||||
"description": "Percent represents a value between 0 and 100% (i.e. between 0.0 and 1.0)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Decimal"
|
||||
}
|
||||
]
|
||||
},
|
||||
"RangedValue_for_Percent": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RangedValue_for_Uint128": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Uint128": {
|
||||
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
|
||||
"type": "string"
|
||||
|
||||
@@ -1055,18 +1055,6 @@
|
||||
"minimum_mixnode_pledge"
|
||||
],
|
||||
"properties": {
|
||||
"interval_operating_cost": {
|
||||
"description": "Defines the allowed interval operating cost range of operators. default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)",
|
||||
"default": {
|
||||
"maximum": "1000000000000000",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Uint128"
|
||||
}
|
||||
]
|
||||
},
|
||||
"minimum_gateway_pledge": {
|
||||
"description": "Minimum amount a gateway must pledge to get into the system.",
|
||||
"allOf": [
|
||||
@@ -1093,18 +1081,6 @@
|
||||
"$ref": "#/definitions/Coin"
|
||||
}
|
||||
]
|
||||
},
|
||||
"profit_margin": {
|
||||
"description": "Defines the allowed profit margin range of operators. default: 0% - 100%",
|
||||
"default": {
|
||||
"maximum": "1",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Percent"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -1439,38 +1415,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"RangedValue_for_Percent": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RangedValue_for_Uint128": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Uint128": {
|
||||
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
|
||||
"type": "string"
|
||||
|
||||
@@ -22,28 +22,6 @@
|
||||
"initial_rewarding_params": {
|
||||
"$ref": "#/definitions/InitialRewardingParams"
|
||||
},
|
||||
"interval_operating_cost": {
|
||||
"default": {
|
||||
"maximum": "1000000000000000",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Uint128"
|
||||
}
|
||||
]
|
||||
},
|
||||
"profit_margin": {
|
||||
"default": {
|
||||
"maximum": "1",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Percent"
|
||||
}
|
||||
]
|
||||
},
|
||||
"rewarding_denom": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -130,42 +108,6 @@
|
||||
"$ref": "#/definitions/Decimal"
|
||||
}
|
||||
]
|
||||
},
|
||||
"RangedValue_for_Percent": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RangedValue_for_Uint128": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Uint128": {
|
||||
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,18 +77,6 @@
|
||||
"minimum_mixnode_pledge"
|
||||
],
|
||||
"properties": {
|
||||
"interval_operating_cost": {
|
||||
"description": "Defines the allowed interval operating cost range of operators. default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)",
|
||||
"default": {
|
||||
"maximum": "1000000000000000",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Uint128"
|
||||
}
|
||||
]
|
||||
},
|
||||
"minimum_gateway_pledge": {
|
||||
"description": "Minimum amount a gateway must pledge to get into the system.",
|
||||
"allOf": [
|
||||
@@ -115,62 +103,6 @@
|
||||
"$ref": "#/definitions/Coin"
|
||||
}
|
||||
]
|
||||
},
|
||||
"profit_margin": {
|
||||
"description": "Defines the allowed profit margin range of operators. default: 0% - 100%",
|
||||
"default": {
|
||||
"maximum": "1",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Percent"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Decimal": {
|
||||
"description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)",
|
||||
"type": "string"
|
||||
},
|
||||
"Percent": {
|
||||
"description": "Percent represents a value between 0 and 100% (i.e. between 0.0 and 1.0)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Decimal"
|
||||
}
|
||||
]
|
||||
},
|
||||
"RangedValue_for_Percent": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RangedValue_for_Uint128": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
||||
@@ -8,18 +8,6 @@
|
||||
"minimum_mixnode_pledge"
|
||||
],
|
||||
"properties": {
|
||||
"interval_operating_cost": {
|
||||
"description": "Defines the allowed interval operating cost range of operators. default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)",
|
||||
"default": {
|
||||
"maximum": "1000000000000000",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Uint128"
|
||||
}
|
||||
]
|
||||
},
|
||||
"minimum_gateway_pledge": {
|
||||
"description": "Minimum amount a gateway must pledge to get into the system.",
|
||||
"allOf": [
|
||||
@@ -46,18 +34,6 @@
|
||||
"$ref": "#/definitions/Coin"
|
||||
}
|
||||
]
|
||||
},
|
||||
"profit_margin": {
|
||||
"description": "Defines the allowed profit margin range of operators. default: 0% - 100%",
|
||||
"default": {
|
||||
"maximum": "1",
|
||||
"minimum": "0"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/RangedValue_for_Percent"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@@ -77,50 +53,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Decimal": {
|
||||
"description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)",
|
||||
"type": "string"
|
||||
},
|
||||
"Percent": {
|
||||
"description": "Percent represents a value between 0 and 100% (i.e. between 0.0 and 1.0)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Decimal"
|
||||
}
|
||||
]
|
||||
},
|
||||
"RangedValue_for_Percent": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Percent"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RangedValue_for_Uint128": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"maximum",
|
||||
"minimum"
|
||||
],
|
||||
"properties": {
|
||||
"maximum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
},
|
||||
"minimum": {
|
||||
"$ref": "#/definitions/Uint128"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Uint128": {
|
||||
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
|
||||
"type": "string"
|
||||
|
||||
@@ -11,8 +11,7 @@ use cosmwasm_std::{
|
||||
};
|
||||
use mixnet_contract_common::error::MixnetContractError;
|
||||
use mixnet_contract_common::{
|
||||
ContractState, ContractStateParams, ExecuteMsg, InstantiateMsg, Interval, MigrateMsg,
|
||||
OperatingCostRange, ProfitMarginRange, QueryMsg,
|
||||
ContractState, ContractStateParams, ExecuteMsg, InstantiateMsg, Interval, MigrateMsg, QueryMsg,
|
||||
};
|
||||
use nym_contracts_common::set_build_information;
|
||||
|
||||
@@ -25,8 +24,6 @@ fn default_initial_state(
|
||||
rewarding_validator_address: Addr,
|
||||
rewarding_denom: String,
|
||||
vesting_contract_address: Addr,
|
||||
profit_margin: ProfitMarginRange,
|
||||
interval_operating_cost: OperatingCostRange,
|
||||
) -> ContractState {
|
||||
ContractState {
|
||||
owner,
|
||||
@@ -43,8 +40,6 @@ fn default_initial_state(
|
||||
denom: rewarding_denom,
|
||||
amount: INITIAL_GATEWAY_PLEDGE_AMOUNT,
|
||||
},
|
||||
profit_margin,
|
||||
interval_operating_cost,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -76,8 +71,6 @@ pub fn instantiate(
|
||||
rewarding_validator_address.clone(),
|
||||
msg.rewarding_denom,
|
||||
vesting_contract_address,
|
||||
msg.profit_margin,
|
||||
msg.interval_operating_cost,
|
||||
);
|
||||
let starting_interval =
|
||||
Interval::init_interval(msg.epochs_in_interval, msg.epoch_duration, &env);
|
||||
@@ -638,7 +631,7 @@ pub fn migrate(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
|
||||
use cosmwasm_std::{Decimal, Uint128};
|
||||
use cosmwasm_std::Decimal;
|
||||
use mixnet_contract_common::reward_params::{IntervalRewardParams, RewardingParams};
|
||||
use mixnet_contract_common::{InitialRewardingParams, Percent};
|
||||
use std::time::Duration;
|
||||
@@ -664,14 +657,6 @@ mod tests {
|
||||
rewarded_set_size: 543,
|
||||
active_set_size: 123,
|
||||
},
|
||||
profit_margin: ProfitMarginRange {
|
||||
minimum: "0.05".parse().unwrap(),
|
||||
maximum: "0.95".parse().unwrap(),
|
||||
},
|
||||
interval_operating_cost: OperatingCostRange {
|
||||
minimum: "1000".parse().unwrap(),
|
||||
maximum: "10000".parse().unwrap(),
|
||||
},
|
||||
};
|
||||
|
||||
let sender = mock_info("sender", &[]);
|
||||
@@ -693,14 +678,6 @@ mod tests {
|
||||
denom: "uatom".into(),
|
||||
amount: INITIAL_GATEWAY_PLEDGE_AMOUNT,
|
||||
},
|
||||
profit_margin: ProfitMarginRange {
|
||||
minimum: Percent::from_percentage_value(5).unwrap(),
|
||||
maximum: Percent::from_percentage_value(95).unwrap(),
|
||||
},
|
||||
interval_operating_cost: OperatingCostRange {
|
||||
minimum: Uint128::new(1000),
|
||||
maximum: Uint128::new(10000),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -45,8 +45,6 @@ pub(crate) mod tests {
|
||||
minimum_mixnode_delegation: None,
|
||||
minimum_mixnode_pledge: coin(123u128, "unym"),
|
||||
minimum_gateway_pledge: coin(456u128, "unym"),
|
||||
profit_margin: Default::default(),
|
||||
interval_operating_cost: Default::default(),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use cosmwasm_std::{Addr, Storage};
|
||||
use cosmwasm_std::{Coin, StdResult};
|
||||
use cw_storage_plus::Item;
|
||||
use mixnet_contract_common::error::MixnetContractError;
|
||||
use mixnet_contract_common::{ContractState, OperatingCostRange, ProfitMarginRange};
|
||||
use mixnet_contract_common::ContractState;
|
||||
|
||||
pub(crate) const CONTRACT_STATE: Item<'_, ContractState> = Item::new(CONTRACT_STATE_KEY);
|
||||
|
||||
@@ -28,22 +28,6 @@ pub(crate) fn minimum_gateway_pledge(storage: &dyn Storage) -> Result<Coin, Mixn
|
||||
.map(|state| state.params.minimum_gateway_pledge)?)
|
||||
}
|
||||
|
||||
pub(crate) fn profit_margin_range(
|
||||
storage: &dyn Storage,
|
||||
) -> Result<ProfitMarginRange, MixnetContractError> {
|
||||
Ok(CONTRACT_STATE
|
||||
.load(storage)
|
||||
.map(|state| state.params.profit_margin)?)
|
||||
}
|
||||
|
||||
pub(crate) fn interval_oprating_cost_range(
|
||||
storage: &dyn Storage,
|
||||
) -> Result<OperatingCostRange, MixnetContractError> {
|
||||
Ok(CONTRACT_STATE
|
||||
.load(storage)
|
||||
.map(|state| state.params.interval_operating_cost)?)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn minimum_delegation_stake(
|
||||
storage: &dyn Storage,
|
||||
|
||||
@@ -121,8 +121,6 @@ pub mod tests {
|
||||
denom,
|
||||
amount: INITIAL_GATEWAY_PLEDGE_AMOUNT + Uint128::new(1234),
|
||||
},
|
||||
profit_margin: Default::default(),
|
||||
interval_operating_cost: Default::default(),
|
||||
};
|
||||
|
||||
let initial_params = storage::CONTRACT_STATE
|
||||
|
||||
@@ -25,8 +25,7 @@ use crate::mixnodes::signature_helpers::verify_mixnode_bonding_signature;
|
||||
use crate::signing::storage as signing_storage;
|
||||
use crate::support::helpers::{
|
||||
ensure_bonded, ensure_epoch_in_progress_state, ensure_is_authorized, ensure_no_existing_bond,
|
||||
ensure_no_pending_pledge_changes, ensure_operating_cost_within_range,
|
||||
ensure_profit_margin_within_range, ensure_proxy_match, ensure_sent_by_vesting_contract,
|
||||
ensure_no_pending_pledge_changes, ensure_proxy_match, ensure_sent_by_vesting_contract,
|
||||
validate_pledge,
|
||||
};
|
||||
|
||||
@@ -122,12 +121,6 @@ fn _try_add_mixnode(
|
||||
owner_signature: MessageSignature,
|
||||
proxy: Option<Addr>,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
// ensure the profit margin is within the defined range
|
||||
ensure_profit_margin_within_range(deps.storage, cost_params.profit_margin_percent)?;
|
||||
|
||||
// ensure the operating cost is within the defined range
|
||||
ensure_operating_cost_within_range(deps.storage, &cost_params.interval_operating_cost)?;
|
||||
|
||||
// check if the pledge contains any funds of the appropriate denomination
|
||||
let minimum_pledge = mixnet_params_storage::minimum_mixnode_pledge(deps.storage)?;
|
||||
let pledge = validate_pledge(pledge, minimum_pledge)?;
|
||||
@@ -484,12 +477,6 @@ pub(crate) fn _try_update_mixnode_cost_params(
|
||||
ensure_proxy_match(&proxy, &existing_bond.proxy)?;
|
||||
ensure_bonded(&existing_bond)?;
|
||||
|
||||
// ensure the profit margin is within the defined range
|
||||
ensure_profit_margin_within_range(deps.storage, new_costs.profit_margin_percent)?;
|
||||
|
||||
// ensure the operating cost is within the defined range
|
||||
ensure_operating_cost_within_range(deps.storage, &new_costs.interval_operating_cost)?;
|
||||
|
||||
let cosmos_event = new_mixnode_pending_cost_params_update_event(
|
||||
existing_bond.mix_id,
|
||||
&owner,
|
||||
|
||||
@@ -111,14 +111,6 @@ pub(crate) fn try_reward_mixnode(
|
||||
);
|
||||
}
|
||||
|
||||
// make sure node's profit margin is within the allowed range,
|
||||
// if not adjust it accordingly
|
||||
let params = mixnet_params_storage::CONTRACT_STATE
|
||||
.load(deps.storage)?
|
||||
.params;
|
||||
mix_rewarding.normalise_profit_margin(params.profit_margin);
|
||||
mix_rewarding.normalise_operating_cost(params.interval_operating_cost);
|
||||
|
||||
let rewarding_params = storage::REWARDING_PARAMS.load(deps.storage)?;
|
||||
let node_reward_params = NodeRewardParams::new(node_performance, node_status.is_active());
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ use cosmwasm_std::{wasm_execute, Addr, BankMsg, Coin, CosmosMsg, MessageInfo, Re
|
||||
use mixnet_contract_common::error::MixnetContractError;
|
||||
use mixnet_contract_common::mixnode::PendingMixNodeChanges;
|
||||
use mixnet_contract_common::{EpochState, EpochStatus, IdentityKeyRef, MixId, MixNodeBond};
|
||||
use nym_contracts_common::Percent;
|
||||
use vesting_contract_common::messages::ExecuteMsg as VestingContractExecuteMsg;
|
||||
|
||||
// helper trait to attach `Msg` to a response if it's provided
|
||||
@@ -432,34 +431,3 @@ pub(crate) fn decode_ed25519_identity_key(
|
||||
|
||||
Ok(public_key)
|
||||
}
|
||||
|
||||
pub(crate) fn ensure_profit_margin_within_range(
|
||||
storage: &dyn Storage,
|
||||
profit_margin: Percent,
|
||||
) -> Result<(), MixnetContractError> {
|
||||
let range = mixnet_params_storage::profit_margin_range(storage)?;
|
||||
if !range.within_range(profit_margin) {
|
||||
return Err(MixnetContractError::ProfitMarginOutsideRange {
|
||||
provided: profit_margin,
|
||||
range,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn ensure_operating_cost_within_range(
|
||||
storage: &dyn Storage,
|
||||
operating_cost: &Coin,
|
||||
) -> Result<(), MixnetContractError> {
|
||||
let range = mixnet_params_storage::interval_oprating_cost_range(storage)?;
|
||||
if !range.within_range(operating_cost.amount) {
|
||||
return Err(MixnetContractError::OperatingCostOutsideRange {
|
||||
denom: operating_cost.denom.clone(),
|
||||
provided: operating_cost.amount,
|
||||
range,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1258,8 +1258,6 @@ pub mod test_helpers {
|
||||
epochs_in_interval: 720,
|
||||
epoch_duration: Duration::from_secs(60 * 60),
|
||||
initial_rewarding_params: initial_rewarding_params(),
|
||||
profit_margin: Default::default(),
|
||||
interval_operating_cost: Default::default(),
|
||||
};
|
||||
let env = mock_env();
|
||||
let info = mock_info("creator", &[]);
|
||||
|
||||
@@ -42,17 +42,17 @@ This page displays a full list of all the changes during our release cycle from
|
||||
|
||||
### Features
|
||||
|
||||
- [Remove the `nym-mixnode` and `nym-gateway` binaries from the CI upload builds action](https://github.com/nymtech/nym/pull/4693):
|
||||
- [Remove the `nym-mixnode` and `nym-gateway` binaries from the CI upload builds action](https://github.com/nymtech/nym/pull/4693):
|
||||
- [Add an early return in `parse_raw_str_logs` for empty raw log strings.](https://github.com/nymtech/nym/pull/4686): This accommodates for the v50 + chain upgrade.
|
||||
- [Bump braces from `3.0.2` to `3.0.3` in `/wasm/mix-fetch/internal-dev`](https://github.com/nymtech/nym/pull/4672): Version update of [braces](https://github.com/micromatch/braces)
|
||||
- [Bump braces from `3.0.2` to `3.0.3` in `/clients/native/examples/js-examples/websocket`](https://github.com/nymtech/nym/pull/4663): Version update of [braces](https://github.com/micromatch/braces).
|
||||
- [Bump braces from `3.0.2` to `3.0.3` in `/nym-api/tests`](https://github.com/nymtech/nym/pull/4659): Version update of [braces](https://github.com/micromatch/braces).
|
||||
- [Bump braces from `3.0.2` to `3.0.3` in `/docker/typescript_client/upload_contract`](https://github.com/nymtech/nym/pull/4658): Version update of [braces](https://github.com/micromatch/braces).
|
||||
- [Bump `ws` from `8.13.0` to `8.17.1` in `/wasm/client/internal-dev-node`](https://github.com/nymtech/nym/pull/4665): Version update of [`ws`](https://github.com/websockets/ws).
|
||||
- [Bump `ws` from `8.14.2` to `8.17.1` in `/sdk/typescript/packages/nodejs-client`](https://github.com/nymtech/nym/pull/4662): Version update of [`ws`](https://github.com/websockets/ws).
|
||||
- [Bump `ws` from `8.13.0` to `8.17.1` in `/wasm/client/internal-dev-node`](https://github.com/nymtech/nym/pull/4665): Version update of [`ws`](https://github.com/websockets/ws).
|
||||
- [Bump `ws` from `8.14.2` to `8.17.1` in `/sdk/typescript/packages/nodejs-client`](https://github.com/nymtech/nym/pull/4662): Version update of [`ws`](https://github.com/websockets/ws).
|
||||
- [Add expiry returned on import](https://github.com/nymtech/nym/pull/4670): We need to return the expiry on import for desktop daemon `nym-vpnd`.
|
||||
- [New clippy lints](https://github.com/nymtech/nym/pull/4660)
|
||||
- [Remove `nym-connect` directory](https://github.com/nymtech/nym/pull/4643): Since the `nym-vpn` has superseded `nym-connect`, remove `nym-connect` from the repo.
|
||||
- [Remove `nym-connect` directory](https://github.com/nymtech/nym/pull/4643): Since the `nym-vpn` has superseded `nym-connect`, remove `nym-connect` from the repo.
|
||||
- [Remove old PR template](https://github.com/nymtech/nym/pull/4639)
|
||||
|
||||
### Bugfix
|
||||
@@ -62,7 +62,7 @@ This page displays a full list of all the changes during our release cycle from
|
||||
### Operators Guide updates
|
||||
|
||||
- [Node description guide](nodes/configuration.md#node-description): Steps to add self-description to `nym-node` and query this information from any node.
|
||||
- [Web Secure Socket (WSS) guide and reverse proxy update](/nodes/proxy-configuration.md), PR [here](https://github.com/nymtech/nym/pull/4694): A guide to setup `nym-node` in a secure fashion, using WSS via Nginx and Certbot. Landing page (reversed proxy) is updated and simplified.
|
||||
- [Web Secure Socket (WSS) guide and reverse proxy update](nodes/proxy-configuration.md), PR [here](https://github.com/nymtech/nym/pull/4694): A guide to setup `nym-node` in a secure fashion, using WSS via Nginx and Certbot. Landing page (reversed proxy) is updated and simplified.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ You can bond your `nym-node` via the Desktop wallet.
|
||||
| :-- | :-- | :-- |
|
||||
| Mixnode | Mix port | `1789` |
|
||||
| Mixnode | Verloc port | `1790` |
|
||||
| Mixnode | HTTP api port (picture below) | `8080` |
|
||||
| Mixnode | HTTP api port (picture below) | `8080` |
|
||||
| Gateway (entry & exit) | Mix port | `1789` |
|
||||
| Gateway (entry & exit) | Client WS API port | `9000` |
|
||||
|
||||
@@ -59,6 +59,7 @@ You can bond your `nym-node` via the Desktop wallet.
|
||||
```
|
||||
|
||||

|
||||
|
||||
*This image is just an example, copy-paste your own base58-encoded signature*
|
||||
|
||||
6. Your node will now be bonded and ready to recieve traffic, latest at the beginning of the next epoch (at most 1 hour)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
{
|
||||
"extends": ["next/core-web-vitals"]
|
||||
"extends": ["next/core-web-vitals"],
|
||||
"rules": {
|
||||
"react-hooks/exhaustive-deps": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React from 'react'
|
||||
import { Navbar } from './components/Nav/Navbar'
|
||||
import { Providers } from './providers'
|
||||
import React from "react";
|
||||
import { Navbar } from "./components/Nav/Navbar";
|
||||
import { Providers } from "./providers";
|
||||
|
||||
const App = ({ children }: { children: React.ReactNode }) => (
|
||||
const App = ({ children }: { children: any }) => (
|
||||
<Providers>
|
||||
<Navbar>{children}</Navbar>
|
||||
</Providers>
|
||||
)
|
||||
);
|
||||
|
||||
export { App }
|
||||
export { App };
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Typography } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { Typography } from "@mui/material";
|
||||
import * as React from "react";
|
||||
|
||||
export const ComponentError: FCWithChildren<{ text: string }> = ({ text }) => (
|
||||
export const ComponentError = ({ text }: { text: string }) => (
|
||||
<Typography
|
||||
sx={{ marginTop: 2, color: 'primary.main', fontSize: 10 }}
|
||||
sx={{ marginTop: 2, color: "primary.main", fontSize: 10 }}
|
||||
variant="body1"
|
||||
data-testid="delegation-total-amount"
|
||||
>
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { Card, CardHeader, CardContent, Typography } from '@mui/material'
|
||||
import React, { ReactEventHandler } from 'react'
|
||||
import React, { ReactEventHandler } from "react";
|
||||
import { Card, CardHeader, CardContent, Typography } from "@mui/material";
|
||||
|
||||
type ContentCardProps = {
|
||||
title?: React.ReactNode
|
||||
subtitle?: string
|
||||
Icon?: React.ReactNode
|
||||
Action?: React.ReactNode
|
||||
errorMsg?: string
|
||||
onClick?: ReactEventHandler
|
||||
}
|
||||
title?: React.ReactNode;
|
||||
subtitle?: string;
|
||||
Icon?: React.ReactNode;
|
||||
Action?: React.ReactNode;
|
||||
errorMsg?: string;
|
||||
children: React.ReactNode;
|
||||
onClick?: ReactEventHandler;
|
||||
};
|
||||
|
||||
export const ContentCard: FCWithChildren<ContentCardProps> = ({
|
||||
export const ContentCard = ({
|
||||
title,
|
||||
Icon,
|
||||
Action,
|
||||
@@ -18,11 +19,11 @@ export const ContentCard: FCWithChildren<ContentCardProps> = ({
|
||||
errorMsg,
|
||||
children,
|
||||
onClick,
|
||||
}) => (
|
||||
<Card onClick={onClick} sx={{ height: '100%' }}>
|
||||
}: ContentCardProps) => (
|
||||
<Card onClick={onClick} sx={{ height: "100%" }}>
|
||||
{title && (
|
||||
<CardHeader
|
||||
title={title || ''}
|
||||
title={title || ""}
|
||||
avatar={Icon}
|
||||
action={Action}
|
||||
subheader={subtitle}
|
||||
@@ -30,9 +31,9 @@ export const ContentCard: FCWithChildren<ContentCardProps> = ({
|
||||
)}
|
||||
{children && <CardContent>{children}</CardContent>}
|
||||
{errorMsg && (
|
||||
<Typography variant="body2" sx={{ color: 'danger', padding: 2 }}>
|
||||
<Typography variant="body2" sx={{ color: "danger", padding: 2 }}>
|
||||
{errorMsg}
|
||||
</Typography>
|
||||
)}
|
||||
</Card>
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import * as React from 'react'
|
||||
import { Box, Typography } from '@mui/material'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
import { Tooltip } from '@nymproject/react/tooltip/Tooltip'
|
||||
import * as React from "react";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { Tooltip } from "@nymproject/react";
|
||||
import { InfoOutlined } from "@mui/icons-material";
|
||||
|
||||
export const CustomColumnHeading: FCWithChildren<{
|
||||
headingTitle: string
|
||||
tooltipInfo?: string
|
||||
headingTitle: string;
|
||||
tooltipInfo?: string;
|
||||
}> = ({ headingTitle, tooltipInfo }) => {
|
||||
const theme = useTheme()
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Box alignItems="center" display="flex">
|
||||
@@ -20,11 +21,12 @@ export const CustomColumnHeading: FCWithChildren<{
|
||||
bgColor={theme.palette.nym.networkExplorer.tooltip.background}
|
||||
maxWidth={230}
|
||||
arrow
|
||||
TooltipIcon={<InfoOutlined sx={{ width: 18, height: 18, mr: 1 }} />}
|
||||
/>
|
||||
)}
|
||||
<Typography variant="body2" fontWeight={600} data-testid={headingTitle}>
|
||||
{headingTitle}
|
||||
</Typography>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import React, { useState } from 'react'
|
||||
import { Box, SxProps } from '@mui/material'
|
||||
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField'
|
||||
import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField'
|
||||
import { CurrencyDenom, DecCoin } from '@nymproject/types'
|
||||
import { useWalletContext } from '@/app/context/wallet'
|
||||
import { urls } from '@/app/utils'
|
||||
import { useDelegationsContext } from '@/app/context/delegations'
|
||||
import { validateAmount } from '@/app/utils/currency'
|
||||
import { SimpleModal } from './SimpleModal'
|
||||
import { ModalListItem } from './ModalListItem'
|
||||
import { DelegationModalProps } from './DelegationModal'
|
||||
import React, { useState } from "react";
|
||||
import { Box, SxProps } from "@mui/material";
|
||||
import { IdentityKeyFormField } from "@nymproject/react";
|
||||
import { CurrencyFormField } from "@nymproject/react";
|
||||
import { CurrencyDenom, DecCoin } from "@nymproject/types";
|
||||
import { useWalletContext } from "@/app/context/wallet";
|
||||
import { urls } from "@/app/utils";
|
||||
import { useDelegationsContext } from "@/app/context/delegations";
|
||||
import { validateAmount } from "@/app/utils/currency";
|
||||
import { SimpleModal } from "./SimpleModal";
|
||||
import { ModalListItem } from "./ModalListItem";
|
||||
import { DelegationModalProps } from "./DelegationModal";
|
||||
|
||||
const MIN_AMOUNT_TO_DELEGATE = 10
|
||||
const MIN_AMOUNT_TO_DELEGATE = 10;
|
||||
|
||||
type Props = {
|
||||
mixId: number
|
||||
identityKey: string
|
||||
header?: string
|
||||
buttonText?: string
|
||||
rewardInterval?: string
|
||||
estimatedReward?: number
|
||||
profitMarginPercentage?: string | null
|
||||
nodeUptimePercentage?: number | null
|
||||
denom: CurrencyDenom
|
||||
sx?: SxProps
|
||||
backdropProps?: object
|
||||
onClose: () => void
|
||||
onOk?: (delegationModalProps: DelegationModalProps) => void
|
||||
}
|
||||
mixId: number;
|
||||
identityKey: string;
|
||||
header?: string;
|
||||
buttonText?: string;
|
||||
rewardInterval?: string;
|
||||
estimatedReward?: number;
|
||||
profitMarginPercentage?: string | null;
|
||||
nodeUptimePercentage?: number | null;
|
||||
denom: CurrencyDenom;
|
||||
sx?: SxProps;
|
||||
backdropProps?: object;
|
||||
onClose: () => void;
|
||||
onOk?: (delegationModalProps: DelegationModalProps) => void;
|
||||
};
|
||||
|
||||
export const DelegateModal = ({
|
||||
mixId,
|
||||
@@ -40,106 +40,106 @@ export const DelegateModal = ({
|
||||
sx,
|
||||
}: Props) => {
|
||||
const [amount, setAmount] = useState<DecCoin | undefined>({
|
||||
amount: '10',
|
||||
denom: 'nym',
|
||||
})
|
||||
const [isValidated, setValidated] = useState<boolean>(false)
|
||||
const [errorAmount, setErrorAmount] = useState<string | undefined>()
|
||||
amount: "10",
|
||||
denom: "nym",
|
||||
});
|
||||
const [isValidated, setValidated] = useState<boolean>(false);
|
||||
const [errorAmount, setErrorAmount] = useState<string | undefined>();
|
||||
|
||||
const { address, balance } = useWalletContext()
|
||||
const { handleDelegate } = useDelegationsContext()
|
||||
const { address, balance } = useWalletContext();
|
||||
const { handleDelegate } = useDelegationsContext();
|
||||
|
||||
const validate = async () => {
|
||||
let newValidatedValue = true
|
||||
let errorAmountMessage
|
||||
let newValidatedValue = true;
|
||||
let errorAmountMessage;
|
||||
|
||||
if (amount && !(await validateAmount(amount.amount, '0'))) {
|
||||
newValidatedValue = false
|
||||
errorAmountMessage = 'Please enter a valid amount'
|
||||
if (amount && !(await validateAmount(amount.amount, "0"))) {
|
||||
newValidatedValue = false;
|
||||
errorAmountMessage = "Please enter a valid amount";
|
||||
}
|
||||
|
||||
if (amount && +amount.amount < MIN_AMOUNT_TO_DELEGATE) {
|
||||
errorAmountMessage = `Min. delegation amount: ${MIN_AMOUNT_TO_DELEGATE} ${denom.toUpperCase()}`
|
||||
newValidatedValue = false
|
||||
errorAmountMessage = `Min. delegation amount: ${MIN_AMOUNT_TO_DELEGATE} ${denom.toUpperCase()}`;
|
||||
newValidatedValue = false;
|
||||
}
|
||||
|
||||
if (!amount?.amount.length) {
|
||||
newValidatedValue = false
|
||||
newValidatedValue = false;
|
||||
}
|
||||
|
||||
if (amount && balance.data && +balance.data - +amount.amount <= 0) {
|
||||
errorAmountMessage = 'Not enough funds'
|
||||
newValidatedValue = false
|
||||
errorAmountMessage = "Not enough funds";
|
||||
newValidatedValue = false;
|
||||
}
|
||||
|
||||
setErrorAmount(errorAmountMessage)
|
||||
setValidated(newValidatedValue)
|
||||
}
|
||||
setErrorAmount(errorAmountMessage);
|
||||
setValidated(newValidatedValue);
|
||||
};
|
||||
|
||||
const delegateToMixnode = async ({
|
||||
delegationMixId,
|
||||
delegationAmount,
|
||||
}: {
|
||||
delegationMixId: number
|
||||
delegationAmount: string
|
||||
delegationMixId: number;
|
||||
delegationAmount: string;
|
||||
}) => {
|
||||
try {
|
||||
const tx = await handleDelegate(delegationMixId, delegationAmount)
|
||||
return tx
|
||||
const tx = await handleDelegate(delegationMixId, delegationAmount);
|
||||
return tx;
|
||||
} catch (e) {
|
||||
console.error('Failed to delegate to mixnode', e)
|
||||
throw e
|
||||
console.error("Failed to delegate to mixnode", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (mixId && amount && onOk) {
|
||||
onOk({
|
||||
status: 'loading',
|
||||
})
|
||||
status: "loading",
|
||||
});
|
||||
try {
|
||||
if (!address) {
|
||||
throw new Error('Please connect your wallet')
|
||||
throw new Error("Please connect your wallet");
|
||||
}
|
||||
|
||||
const tx = await delegateToMixnode({
|
||||
delegationMixId: mixId,
|
||||
delegationAmount: amount.amount,
|
||||
})
|
||||
});
|
||||
|
||||
if (!tx) {
|
||||
throw new Error('Failed to delegate')
|
||||
throw new Error("Failed to delegate");
|
||||
}
|
||||
|
||||
onOk({
|
||||
status: 'success',
|
||||
message: 'Delegation can take up to one hour to process',
|
||||
status: "success",
|
||||
message: "Delegation can take up to one hour to process",
|
||||
transactions: [
|
||||
{
|
||||
url: `${urls('MAINNET').blockExplorer}/transaction/${
|
||||
url: `${urls("MAINNET").blockExplorer}/transaction/${
|
||||
tx.transactionHash
|
||||
}`,
|
||||
hash: tx.transactionHash,
|
||||
},
|
||||
],
|
||||
})
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Failed to delegate', e)
|
||||
console.error("Failed to delegate", e);
|
||||
onOk({
|
||||
status: 'error',
|
||||
status: "error",
|
||||
message: (e as Error).message,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleAmountChanged = (newAmount: DecCoin) => {
|
||||
setAmount(newAmount)
|
||||
}
|
||||
setAmount(newAmount);
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
validate()
|
||||
}, [amount, identityKey, mixId])
|
||||
validate();
|
||||
}, [amount, identityKey, mixId]);
|
||||
|
||||
return (
|
||||
<SimpleModal
|
||||
@@ -170,7 +170,7 @@ export const DelegateModal = ({
|
||||
fullWidth
|
||||
autoFocus
|
||||
label="Amount"
|
||||
initialValue={amount?.amount || '10'}
|
||||
initialValue={amount?.amount || "10"}
|
||||
onChanged={handleAmountChanged}
|
||||
denom={denom}
|
||||
validationError={errorAmount}
|
||||
@@ -187,5 +187,5 @@ export const DelegateModal = ({
|
||||
|
||||
<ModalListItem label="Est. fee for this transaction will be calculated in your connected wallet" />
|
||||
</SimpleModal>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import React from 'react'
|
||||
import { Typography, SxProps, Stack } from '@mui/material'
|
||||
import { Link } from '@nymproject/react/link/Link'
|
||||
import { LoadingModal } from './LoadingModal'
|
||||
import { ConfirmationModal } from './ConfirmationModal'
|
||||
import { ErrorModal } from './ErrorModal'
|
||||
import React from "react";
|
||||
import { Typography, SxProps, Stack } from "@mui/material";
|
||||
import { Link } from "@nymproject/react";
|
||||
import { LoadingModal } from "./LoadingModal";
|
||||
import { ConfirmationModal } from "./ConfirmationModal";
|
||||
import { ErrorModal } from "./ErrorModal";
|
||||
|
||||
export type DelegationModalProps = {
|
||||
status: 'loading' | 'success' | 'error' | 'info'
|
||||
message?: string
|
||||
status: "loading" | "success" | "error" | "info";
|
||||
message?: string;
|
||||
transactions?: {
|
||||
url: string
|
||||
hash: string
|
||||
}[]
|
||||
}
|
||||
url: string;
|
||||
hash: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
export const DelegationModal: FCWithChildren<
|
||||
DelegationModalProps & {
|
||||
open: boolean
|
||||
onClose: () => void
|
||||
sx?: SxProps
|
||||
backdropProps?: object
|
||||
children?: React.ReactNode
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
sx?: SxProps;
|
||||
backdropProps?: object;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
> = ({
|
||||
status,
|
||||
@@ -32,18 +32,18 @@ export const DelegationModal: FCWithChildren<
|
||||
sx,
|
||||
backdropProps,
|
||||
}) => {
|
||||
if (status === 'loading')
|
||||
return <LoadingModal sx={sx} backdropProps={backdropProps} />
|
||||
if (status === "loading")
|
||||
return <LoadingModal sx={sx} backdropProps={backdropProps} />;
|
||||
|
||||
if (status === 'error') {
|
||||
if (status === "error") {
|
||||
return (
|
||||
<ErrorModal message={message} sx={sx} open={open} onClose={onClose}>
|
||||
{children}
|
||||
</ErrorModal>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (status === 'info') {
|
||||
if (status === "info") {
|
||||
return (
|
||||
<ConfirmationModal
|
||||
open={open}
|
||||
@@ -53,7 +53,7 @@ export const DelegationModal: FCWithChildren<
|
||||
>
|
||||
<Typography>{message}</Typography>
|
||||
</ConfirmationModal>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -91,5 +91,5 @@ export const DelegationModal: FCWithChildren<
|
||||
)}
|
||||
</Stack>
|
||||
</ConfirmationModal>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as React from 'react'
|
||||
import * as React from "react";
|
||||
import {
|
||||
Link,
|
||||
Paper,
|
||||
@@ -9,49 +9,49 @@ import {
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCellProps,
|
||||
} from '@mui/material'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
import { Tooltip } from '@nymproject/react/tooltip/Tooltip'
|
||||
import { CopyToClipboard } from '@nymproject/react/clipboard/CopyToClipboard'
|
||||
import { Box } from '@mui/system'
|
||||
import { unymToNym } from '@/app/utils/currency'
|
||||
import { GatewayEnrichedRowType } from './Gateways/Gateways'
|
||||
import { MixnodeRowType } from './MixNodes'
|
||||
import { StakeSaturationProgressBar } from './MixNodes/Economics/StakeSaturationProgressBar'
|
||||
} from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { Tooltip } from "@nymproject/react";
|
||||
import { CopyToClipboard } from "@nymproject/react";
|
||||
import { Box } from "@mui/system";
|
||||
import { unymToNym } from "@/app/utils/currency";
|
||||
import { GatewayEnrichedRowType } from "./Gateways/Gateways";
|
||||
import { MixnodeRowType } from "./MixNodes";
|
||||
import { StakeSaturationProgressBar } from "./MixNodes/Economics/StakeSaturationProgressBar";
|
||||
|
||||
export type ColumnsType = {
|
||||
field: string
|
||||
title: string
|
||||
headerAlign?: TableCellProps['align']
|
||||
width?: string | number
|
||||
tooltipInfo?: string
|
||||
}
|
||||
field: string;
|
||||
title: string;
|
||||
headerAlign?: TableCellProps["align"];
|
||||
width?: string | number;
|
||||
tooltipInfo?: string;
|
||||
};
|
||||
|
||||
export interface UniversalTableProps<T = any> {
|
||||
tableName: string
|
||||
columnsData: ColumnsType[]
|
||||
rows: T[]
|
||||
tableName: string;
|
||||
columnsData: ColumnsType[];
|
||||
rows: T[];
|
||||
}
|
||||
|
||||
function formatCellValues(val: string | number, field: string) {
|
||||
if (field === 'identity_key' && typeof val === 'string') {
|
||||
if (field === "identity_key" && typeof val === "string") {
|
||||
return (
|
||||
<Box display="flex" justifyContent="flex-end">
|
||||
<CopyToClipboard
|
||||
sx={{ mr: 1, mt: 0.5, fontSize: '18px' }}
|
||||
sx={{ mr: 1, mt: 0.5, fontSize: "18px" }}
|
||||
value={val}
|
||||
tooltip={`Copy identity key ${val} to clipboard`}
|
||||
/>
|
||||
<span>{val}</span>
|
||||
</Box>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (field === 'bond') {
|
||||
return unymToNym(val, 6)
|
||||
if (field === "bond") {
|
||||
return unymToNym(val, 6);
|
||||
}
|
||||
|
||||
if (field === 'owner') {
|
||||
if (field === "owner") {
|
||||
return (
|
||||
<Link
|
||||
underline="none"
|
||||
@@ -61,22 +61,22 @@ function formatCellValues(val: string | number, field: string) {
|
||||
>
|
||||
{val}
|
||||
</Link>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (field === 'stake_saturation') {
|
||||
return <StakeSaturationProgressBar value={Number(val)} threshold={100} />
|
||||
if (field === "stake_saturation") {
|
||||
return <StakeSaturationProgressBar value={Number(val)} threshold={100} />;
|
||||
}
|
||||
|
||||
return val
|
||||
return val;
|
||||
}
|
||||
|
||||
export const DetailTable: FCWithChildren<{
|
||||
tableName: string
|
||||
columnsData: ColumnsType[]
|
||||
rows: MixnodeRowType[] | GatewayEnrichedRowType[]
|
||||
tableName: string;
|
||||
columnsData: ColumnsType[];
|
||||
rows: MixnodeRowType[] | GatewayEnrichedRowType[];
|
||||
}> = ({ tableName, columnsData, rows }: UniversalTableProps) => {
|
||||
const theme = useTheme()
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<TableContainer component={Paper}>
|
||||
<Table sx={{ minWidth: 1080 }} aria-label={tableName}>
|
||||
@@ -87,9 +87,9 @@ export const DetailTable: FCWithChildren<{
|
||||
key={field}
|
||||
sx={{ fontSize: 14, fontWeight: 600, width }}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
{tooltipInfo && (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Tooltip
|
||||
title={tooltipInfo}
|
||||
id={field}
|
||||
@@ -115,7 +115,7 @@ export const DetailTable: FCWithChildren<{
|
||||
{rows.map((eachRow) => (
|
||||
<TableRow
|
||||
key={eachRow.id}
|
||||
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
|
||||
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
||||
>
|
||||
{columnsData?.map((data, index) => (
|
||||
<TableCell
|
||||
@@ -128,7 +128,7 @@ export const DetailTable: FCWithChildren<{
|
||||
width: 200,
|
||||
fontSize: 14,
|
||||
}}
|
||||
data-testid={`${data.title.replace(/ /g, '-')}-value`}
|
||||
data-testid={`${data.title.replace(/ /g, "-")}-value`}
|
||||
>
|
||||
{formatCellValues(
|
||||
eachRow[columnsData[index].field],
|
||||
@@ -141,5 +141,5 @@ export const DetailTable: FCWithChildren<{
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
import React from 'react'
|
||||
import Box from '@mui/material/Box'
|
||||
import MuiLink from '@mui/material/Link'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import { useIsMobile } from '../hooks/useIsMobile'
|
||||
import { NymVpnIcon } from '../icons/NymVpn'
|
||||
import { Socials } from './Socials'
|
||||
import Link from 'next/link'
|
||||
import React from "react";
|
||||
import Box from "@mui/material/Box";
|
||||
import MuiLink from "@mui/material/Link";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { useIsMobile } from "../hooks/useIsMobile";
|
||||
import { NymVpnIcon } from "../icons/NymVpn";
|
||||
import { Socials } from "./Socials";
|
||||
import Link from "next/link";
|
||||
|
||||
export const Footer: FCWithChildren = () => {
|
||||
const isMobile = useIsMobile()
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
height: 'auto',
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
bgcolor: "background.default",
|
||||
mt: 3,
|
||||
pt: 3,
|
||||
pb: 3,
|
||||
@@ -25,11 +26,11 @@ export const Footer: FCWithChildren = () => {
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
width: 'auto',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
width: "auto",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
@@ -45,12 +46,12 @@ export const Footer: FCWithChildren = () => {
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: 12,
|
||||
textAlign: isMobile ? 'center' : 'end',
|
||||
color: 'nym.muted.onDarkBg',
|
||||
textAlign: isMobile ? "center" : "end",
|
||||
color: "nym.muted.onDarkBg",
|
||||
}}
|
||||
>
|
||||
© {new Date().getFullYear()} Nym Technologies SA, all rights reserved
|
||||
</Typography>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as React from 'react'
|
||||
import * as React from "react";
|
||||
import {
|
||||
Paper,
|
||||
Table,
|
||||
@@ -8,26 +8,26 @@ import {
|
||||
TableHead,
|
||||
TableRow,
|
||||
Typography,
|
||||
} from '@mui/material'
|
||||
import { Box } from '@mui/system'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
import { Tooltip } from '@nymproject/react/tooltip/Tooltip'
|
||||
import { EconomicsRowsType, EconomicsInfoRowWithIndex } from './types'
|
||||
import { UniversalTableProps } from '@/app/components/DetailTable'
|
||||
import { textColour } from '@/app/utils'
|
||||
} from "@mui/material";
|
||||
import { Box } from "@mui/system";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { Tooltip } from "@nymproject/react";
|
||||
import { EconomicsRowsType, EconomicsInfoRowWithIndex } from "./types";
|
||||
import { UniversalTableProps } from "@/app/components/DetailTable";
|
||||
import { textColour } from "@/app/utils";
|
||||
|
||||
const formatCellValues = (value: EconomicsRowsType, field: string) => (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }} id="field">
|
||||
<Typography sx={{ mr: 1, fontWeight: '600', fontSize: '12px' }} id={field}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }} id="field">
|
||||
<Typography sx={{ mr: 1, fontWeight: "600", fontSize: "12px" }} id={field}>
|
||||
{value.value}
|
||||
</Typography>
|
||||
</Box>
|
||||
)
|
||||
);
|
||||
|
||||
export const DelegatorsInfoTable: FCWithChildren<
|
||||
UniversalTableProps<EconomicsInfoRowWithIndex>
|
||||
> = ({ tableName, columnsData, rows }) => {
|
||||
const theme = useTheme()
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<TableContainer component={Paper}>
|
||||
@@ -39,7 +39,7 @@ export const DelegatorsInfoTable: FCWithChildren<
|
||||
key={field}
|
||||
sx={{ fontSize: 14, fontWeight: 600, width }}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
{tooltipInfo && (
|
||||
<Tooltip
|
||||
title={tooltipInfo}
|
||||
@@ -65,27 +65,27 @@ export const DelegatorsInfoTable: FCWithChildren<
|
||||
{rows?.map((eachRow) => (
|
||||
<TableRow
|
||||
key={eachRow.id}
|
||||
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
|
||||
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
||||
>
|
||||
{columnsData?.map((_, index: number) => {
|
||||
const { field } = columnsData[index]
|
||||
const value: EconomicsRowsType = (eachRow as any)[field]
|
||||
const { field } = columnsData[index];
|
||||
const value: EconomicsRowsType = (eachRow as any)[field];
|
||||
return (
|
||||
<TableCell
|
||||
key={_.title}
|
||||
sx={{
|
||||
color: textColour(value, field, theme),
|
||||
}}
|
||||
data-testid={`${_.title.replace(/ /g, '-')}-value`}
|
||||
data-testid={`${_.title.replace(/ /g, "-")}-value`}
|
||||
>
|
||||
{formatCellValues(value, columnsData[index].field)}
|
||||
</TableCell>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,93 +1,94 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import * as React from 'react'
|
||||
import { ExpandLess, ExpandMore, Menu } from '@mui/icons-material'
|
||||
import { CSSObject, styled, Theme, useTheme } from '@mui/material/styles'
|
||||
import { Link as MuiLink } from '@mui/material'
|
||||
import Button from '@mui/material/Button'
|
||||
import Box from '@mui/material/Box'
|
||||
import ListItem from '@mui/material/ListItem'
|
||||
import MuiDrawer from '@mui/material/Drawer'
|
||||
import AppBar from '@mui/material/AppBar'
|
||||
import Toolbar from '@mui/material/Toolbar'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import List from '@mui/material/List'
|
||||
import IconButton from '@mui/material/IconButton'
|
||||
import ListItemButton from '@mui/material/ListItemButton'
|
||||
import ListItemIcon from '@mui/material/ListItemIcon'
|
||||
import ListItemText from '@mui/material/ListItemText'
|
||||
import { NYM_WEBSITE } from '@/app/api/constants'
|
||||
import { useMainContext } from '@/app/context/main'
|
||||
import { MobileDrawerClose } from '@/app/icons/MobileDrawerClose'
|
||||
import { NavOptionType, originalNavOptions } from '@/app/context/nav'
|
||||
import { DarkLightSwitchDesktop } from '@/app/components/Switch'
|
||||
import { Footer } from '@/app/components/Footer'
|
||||
import { ConnectKeplrWallet } from '@/app/components/Wallet/ConnectKeplrWallet'
|
||||
import { usePathname, useRouter } from 'next/navigation'
|
||||
import * as React from "react";
|
||||
import { Menu } from "@mui/icons-material";
|
||||
import { CSSObject, styled, Theme, useTheme } from "@mui/material/styles";
|
||||
import { Link as MuiLink } from "@mui/material";
|
||||
import Button from "@mui/material/Button";
|
||||
import Box from "@mui/material/Box";
|
||||
import ListItem from "@mui/material/ListItem";
|
||||
import MuiDrawer from "@mui/material/Drawer";
|
||||
import AppBar from "@mui/material/AppBar";
|
||||
import Toolbar from "@mui/material/Toolbar";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import List from "@mui/material/List";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import ListItemButton from "@mui/material/ListItemButton";
|
||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||
import ListItemText from "@mui/material/ListItemText";
|
||||
import { NYM_WEBSITE } from "@/app/api/constants";
|
||||
import { useMainContext } from "@/app/context/main";
|
||||
import { MobileDrawerClose } from "@/app/icons/MobileDrawerClose";
|
||||
import { NavOptionType, originalNavOptions } from "@/app/context/nav";
|
||||
import { DarkLightSwitchDesktop } from "@/app/components/Switch";
|
||||
import { Footer } from "@/app/components/Footer";
|
||||
import { ConnectKeplrWallet } from "@/app/components/Wallet/ConnectKeplrWallet";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { NymLogo } from "@nymproject/react";
|
||||
|
||||
const drawerWidth = 255
|
||||
const bannerHeight = 80
|
||||
const drawerWidth = 255;
|
||||
const bannerHeight = 80;
|
||||
|
||||
const openedMixin = (theme: Theme): CSSObject => ({
|
||||
width: drawerWidth,
|
||||
transition: theme.transitions.create('width', {
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.enteringScreen,
|
||||
}),
|
||||
overflowX: 'hidden',
|
||||
})
|
||||
overflowX: "hidden",
|
||||
});
|
||||
|
||||
const closedMixin = (theme: Theme): CSSObject => ({
|
||||
transition: theme.transitions.create('width', {
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen,
|
||||
}),
|
||||
overflowX: 'hidden',
|
||||
overflowX: "hidden",
|
||||
width: `calc(${theme.spacing(7)} + 1px)`,
|
||||
})
|
||||
});
|
||||
|
||||
const DrawerHeader = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
const DrawerHeader = styled("div")(({ theme }) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
padding: theme.spacing(0, 1),
|
||||
height: 64,
|
||||
}))
|
||||
}));
|
||||
|
||||
const Drawer = styled(MuiDrawer, {
|
||||
shouldForwardProp: (prop) => prop !== 'open',
|
||||
shouldForwardProp: (prop) => prop !== "open",
|
||||
})(({ theme, open }) => ({
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
whiteSpace: 'nowrap',
|
||||
boxSizing: 'border-box',
|
||||
whiteSpace: "nowrap",
|
||||
boxSizing: "border-box",
|
||||
...(open && {
|
||||
...openedMixin(theme),
|
||||
'& .MuiDrawer-paper': openedMixin(theme),
|
||||
"& .MuiDrawer-paper": openedMixin(theme),
|
||||
}),
|
||||
...(!open && {
|
||||
...closedMixin(theme),
|
||||
'& .MuiDrawer-paper': closedMixin(theme),
|
||||
"& .MuiDrawer-paper": closedMixin(theme),
|
||||
}),
|
||||
}))
|
||||
}));
|
||||
|
||||
type ExpandableButtonType = {
|
||||
title: string
|
||||
url: string
|
||||
isActive?: boolean
|
||||
Icon?: React.ReactNode
|
||||
nested?: NavOptionType[]
|
||||
isChild?: boolean
|
||||
isMobile: boolean
|
||||
drawIsTempOpen: boolean
|
||||
drawIsFixed: boolean
|
||||
isExternalLink?: boolean
|
||||
openDrawer: () => void
|
||||
closeDrawer?: () => void
|
||||
fixDrawerClose?: () => void
|
||||
}
|
||||
title: string;
|
||||
url: string;
|
||||
isActive?: boolean;
|
||||
Icon?: React.ReactNode;
|
||||
nested?: NavOptionType[];
|
||||
isChild?: boolean;
|
||||
isMobile: boolean;
|
||||
drawIsTempOpen: boolean;
|
||||
drawIsFixed: boolean;
|
||||
isExternalLink?: boolean;
|
||||
openDrawer: () => void;
|
||||
closeDrawer?: () => void;
|
||||
fixDrawerClose?: () => void;
|
||||
};
|
||||
|
||||
export const ExpandableButton: FCWithChildren<ExpandableButtonType> = ({
|
||||
export const ExpandableButton = ({
|
||||
title,
|
||||
url,
|
||||
drawIsTempOpen,
|
||||
@@ -100,34 +101,34 @@ export const ExpandableButton: FCWithChildren<ExpandableButtonType> = ({
|
||||
openDrawer,
|
||||
closeDrawer,
|
||||
fixDrawerClose,
|
||||
}) => {
|
||||
const { palette } = useTheme()
|
||||
const pathname = usePathname()
|
||||
const router = useRouter()
|
||||
}: ExpandableButtonType) => {
|
||||
const { palette } = useTheme();
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
|
||||
const handleClick = () => {
|
||||
if (title === 'Network Components') {
|
||||
return undefined
|
||||
if (title === "Network Components") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (isExternalLink) {
|
||||
window.open(url, '_blank')
|
||||
window.open(url, "_blank");
|
||||
|
||||
return undefined
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!isExternalLink) {
|
||||
router.push(url, {})
|
||||
router.push(url, {});
|
||||
}
|
||||
|
||||
if (closeDrawer) {
|
||||
closeDrawer()
|
||||
closeDrawer();
|
||||
}
|
||||
}
|
||||
};
|
||||
const selectedStyle = {
|
||||
background: palette.nym.networkExplorer.nav.selected.main,
|
||||
borderRight: `3px solid ${palette.nym.highlight}`,
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -135,12 +136,12 @@ export const ExpandableButton: FCWithChildren<ExpandableButtonType> = ({
|
||||
disablePadding
|
||||
disableGutters
|
||||
sx={{
|
||||
borderBottom: isChild ? 'none' : '1px solid rgba(255, 255, 255, 0.1)',
|
||||
borderBottom: isChild ? "none" : "1px solid rgba(255, 255, 255, 0.1)",
|
||||
...(pathname === url
|
||||
? selectedStyle
|
||||
: {
|
||||
background: palette.nym.networkExplorer.nav.background,
|
||||
borderRight: 'none',
|
||||
borderRight: "none",
|
||||
}),
|
||||
}}
|
||||
>
|
||||
@@ -151,10 +152,10 @@ export const ExpandableButton: FCWithChildren<ExpandableButtonType> = ({
|
||||
pb: 2,
|
||||
background: isChild
|
||||
? palette.nym.networkExplorer.nav.selected.nested
|
||||
: 'none',
|
||||
: "none",
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{ minWidth: '39px' }}>{Icon}</ListItemIcon>
|
||||
<ListItemIcon sx={{ minWidth: "39px" }}>{Icon}</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={title}
|
||||
sx={{
|
||||
@@ -179,52 +180,52 @@ export const ExpandableButton: FCWithChildren<ExpandableButtonType> = ({
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const Nav: FCWithChildren = ({ children }) => {
|
||||
const { environment } = useMainContext()
|
||||
const [drawerIsOpen, setDrawerToOpen] = React.useState(false)
|
||||
const [fixedOpen, setFixedOpen] = React.useState(false)
|
||||
export const Nav = ({ children }: { children: React.ReactNode }) => {
|
||||
const { environment } = useMainContext();
|
||||
const [drawerIsOpen, setDrawerToOpen] = React.useState(false);
|
||||
const [fixedOpen, setFixedOpen] = React.useState(false);
|
||||
// Set maintenance banner to false by default to don't display it
|
||||
const [openMaintenance, setOpenMaintenance] = React.useState(false)
|
||||
const theme = useTheme()
|
||||
const [openMaintenance, setOpenMaintenance] = React.useState(false);
|
||||
const theme = useTheme();
|
||||
|
||||
const explorerName = environment
|
||||
? `${environment} Explorer`
|
||||
: 'Mainnet Explorer'
|
||||
: "Mainnet Explorer";
|
||||
|
||||
const switchNetworkText =
|
||||
environment === 'mainnet' ? 'Switch to Testnet' : 'Switch to Mainnet'
|
||||
environment === "mainnet" ? "Switch to Testnet" : "Switch to Mainnet";
|
||||
const switchNetworkLink =
|
||||
environment === 'mainnet'
|
||||
? 'https://sandbox-explorer.nymtech.net'
|
||||
: 'https://explorer.nymtech.net'
|
||||
environment === "mainnet"
|
||||
? "https://sandbox-explorer.nymtech.net"
|
||||
: "https://explorer.nymtech.net";
|
||||
|
||||
const fixDrawerOpen = () => {
|
||||
setFixedOpen(true)
|
||||
setDrawerToOpen(true)
|
||||
}
|
||||
setFixedOpen(true);
|
||||
setDrawerToOpen(true);
|
||||
};
|
||||
|
||||
const fixDrawerClose = () => {
|
||||
setFixedOpen(false)
|
||||
setDrawerToOpen(false)
|
||||
}
|
||||
setFixedOpen(false);
|
||||
setDrawerToOpen(false);
|
||||
};
|
||||
|
||||
const tempDrawerOpen = () => {
|
||||
if (!fixedOpen) {
|
||||
setDrawerToOpen(true)
|
||||
setDrawerToOpen(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const tempDrawerClose = () => {
|
||||
if (!fixedOpen) {
|
||||
setDrawerToOpen(false)
|
||||
setDrawerToOpen(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex' }}>
|
||||
<Box sx={{ display: "flex" }}>
|
||||
<AppBar
|
||||
sx={{
|
||||
background: theme.palette.nym.networkExplorer.topNav.appBar,
|
||||
@@ -234,28 +235,28 @@ export const Nav: FCWithChildren = ({ children }) => {
|
||||
<Toolbar
|
||||
disableGutters
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
ml: 0.5,
|
||||
}}
|
||||
>
|
||||
<IconButton component="a" href={NYM_WEBSITE} target="_blank">
|
||||
{/* <NymLogo /> */}
|
||||
<NymLogo width={25} />
|
||||
</IconButton>
|
||||
<Typography
|
||||
variant="h6"
|
||||
noWrap
|
||||
sx={{
|
||||
color: theme.palette.nym.networkExplorer.nav.text,
|
||||
fontSize: '18px',
|
||||
fontSize: "18px",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
@@ -274,7 +275,7 @@ export const Nav: FCWithChildren = ({ children }) => {
|
||||
href={switchNetworkLink}
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
textTransform: 'none',
|
||||
textTransform: "none",
|
||||
width: 150,
|
||||
ml: 4,
|
||||
fontSize: 14,
|
||||
@@ -288,19 +289,19 @@ export const Nav: FCWithChildren = ({ children }) => {
|
||||
<Box
|
||||
sx={{
|
||||
mr: 2,
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
width: 'auto',
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
width: "auto",
|
||||
pr: 0,
|
||||
pl: 2,
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
justifyContent: "flex-end",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ mr: 1 }}>
|
||||
@@ -324,10 +325,10 @@ export const Nav: FCWithChildren = ({ children }) => {
|
||||
>
|
||||
<DrawerHeader
|
||||
sx={{
|
||||
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
|
||||
justifyContent: 'flex-start',
|
||||
borderBottom: "1px solid rgba(255, 255, 255, 0.1)",
|
||||
justifyContent: "flex-start",
|
||||
paddingLeft: 0,
|
||||
display: 'none',
|
||||
display: "none",
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
@@ -363,11 +364,11 @@ export const Nav: FCWithChildren = ({ children }) => {
|
||||
</Drawer>
|
||||
<Box
|
||||
style={{ width: `calc(100% - ${drawerWidth}px` }}
|
||||
sx={{ py: 5, px: 6, mt: 7 }}
|
||||
sx={{ py: 5, px: 6, mt: 7, bgcolor: "background.default" }}
|
||||
>
|
||||
{children}
|
||||
<Footer />
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import * as React from 'react'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
import * as React from "react";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import {
|
||||
AppBar,
|
||||
Box,
|
||||
@@ -12,61 +12,58 @@ import {
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
Toolbar,
|
||||
} from '@mui/material'
|
||||
import { Menu } from '@mui/icons-material'
|
||||
import { MaintenanceBanner } from '@nymproject/react/banners/MaintenanceBanner'
|
||||
import { useIsMobile } from '@/app/hooks/useIsMobile'
|
||||
import { MobileDrawerClose } from '@/app/icons/MobileDrawerClose'
|
||||
import { Footer } from '../Footer'
|
||||
import { ExpandableButton } from './DesktopNav'
|
||||
import { ConnectKeplrWallet } from '../Wallet/ConnectKeplrWallet'
|
||||
import { NetworkTitle } from '../NetworkTitle'
|
||||
import { originalNavOptions } from '@/app/context/nav'
|
||||
} from "@mui/material";
|
||||
import { Menu } from "@mui/icons-material";
|
||||
import { useIsMobile } from "@/app/hooks/useIsMobile";
|
||||
import { MobileDrawerClose } from "@/app/icons/MobileDrawerClose";
|
||||
import { Footer } from "../Footer";
|
||||
import { ExpandableButton } from "./DesktopNav";
|
||||
import { ConnectKeplrWallet } from "../Wallet/ConnectKeplrWallet";
|
||||
import { NetworkTitle } from "../NetworkTitle";
|
||||
import { originalNavOptions } from "@/app/context/nav";
|
||||
|
||||
export const MobileNav: FCWithChildren = ({ children }) => {
|
||||
const theme = useTheme()
|
||||
const [drawerOpen, setDrawerOpen] = React.useState(false)
|
||||
export const MobileNav: FCWithChildren<{ children: React.ReactNode }> = ({
|
||||
children,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const [drawerOpen, setDrawerOpen] = React.useState(false);
|
||||
// Set maintenance banner to false by default to don't display it
|
||||
const [openMaintenance, setOpenMaintenance] = React.useState(false)
|
||||
const isSmallMobile = useIsMobile(400)
|
||||
const [openMaintenance, setOpenMaintenance] = React.useState(false);
|
||||
const isSmallMobile = useIsMobile(400);
|
||||
|
||||
const toggleDrawer = () => {
|
||||
setDrawerOpen(!drawerOpen)
|
||||
}
|
||||
setDrawerOpen(!drawerOpen);
|
||||
};
|
||||
|
||||
const openDrawer = () => {
|
||||
setDrawerOpen(true)
|
||||
}
|
||||
setDrawerOpen(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||
<AppBar
|
||||
sx={{
|
||||
background: theme.palette.nym.networkExplorer.topNav.appBar,
|
||||
borderRadius: 0,
|
||||
}}
|
||||
>
|
||||
<MaintenanceBanner
|
||||
open={openMaintenance}
|
||||
onClick={() => setOpenMaintenance(false)}
|
||||
/>
|
||||
<Toolbar
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<IconButton onClick={toggleDrawer}>
|
||||
<Menu sx={{ color: 'primary.contrastText' }} />
|
||||
<Menu sx={{ color: "primary.contrastText" }} />
|
||||
</IconButton>
|
||||
{!isSmallMobile && <NetworkTitle />}
|
||||
</Box>
|
||||
@@ -91,7 +88,7 @@ export const MobileNav: FCWithChildren = ({ children }) => {
|
||||
sx={{
|
||||
height: 64,
|
||||
background: theme.palette.nym.networkExplorer.nav.background,
|
||||
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
|
||||
borderBottom: "1px solid rgba(255, 255, 255, 0.1)",
|
||||
}}
|
||||
>
|
||||
<ListItemButton
|
||||
@@ -100,8 +97,8 @@ export const MobileNav: FCWithChildren = ({ children }) => {
|
||||
pt: 2,
|
||||
pb: 2,
|
||||
background: theme.palette.nym.networkExplorer.nav.background,
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-start',
|
||||
display: "flex",
|
||||
justifyContent: "flex-start",
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
@@ -126,11 +123,10 @@ export const MobileNav: FCWithChildren = ({ children }) => {
|
||||
</List>
|
||||
</Box>
|
||||
</Drawer>
|
||||
|
||||
<Box sx={{ width: '100%', p: 4, mt: 7 }}>
|
||||
<Box sx={{ width: "100%", p: 4, mt: 7, bgcolor: "background.default" }}>
|
||||
{children}
|
||||
<Footer />
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import * as React from 'react';
|
||||
import { Typography } from '@mui/material';
|
||||
import * as React from "react";
|
||||
import { Typography } from "@mui/material";
|
||||
|
||||
export const Title: FCWithChildren<{ text: string }> = ({ text }) => (
|
||||
<Typography
|
||||
variant="h5"
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
color: "text.primary",
|
||||
}}
|
||||
data-testid={text}
|
||||
>
|
||||
|
||||
@@ -1,38 +1,42 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import * as React from 'react'
|
||||
import { scaleLinear } from 'd3-scale'
|
||||
import * as React from "react";
|
||||
import { scaleLinear } from "d3-scale";
|
||||
import {
|
||||
ComposableMap,
|
||||
Geographies,
|
||||
Geography,
|
||||
Marker,
|
||||
ZoomableGroup,
|
||||
} from 'react-simple-maps'
|
||||
import ReactTooltip from 'react-tooltip'
|
||||
import { CircularProgress } from '@mui/material'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
import { ApiState, CountryDataResponse } from '../typeDefs/explorer-api'
|
||||
import MAP_TOPOJSON from '../assets/world-110m.json'
|
||||
} from "react-simple-maps";
|
||||
import { Tooltip as ReactTooltip } from "react-tooltip";
|
||||
import { CircularProgress } from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { ApiState, CountryDataResponse } from "../typeDefs/explorer-api";
|
||||
import MAP_TOPOJSON from "../assets/world-110m.json";
|
||||
|
||||
import "react-tooltip/dist/react-tooltip.css";
|
||||
|
||||
type MapProps = {
|
||||
userLocation?: [number, number]
|
||||
countryData?: ApiState<CountryDataResponse>
|
||||
loading: boolean
|
||||
}
|
||||
userLocation?: [number, number];
|
||||
countryData?: ApiState<CountryDataResponse>;
|
||||
loading: boolean;
|
||||
};
|
||||
|
||||
export const WorldMap: FCWithChildren<MapProps> = ({
|
||||
countryData,
|
||||
userLocation,
|
||||
loading,
|
||||
}) => {
|
||||
const { palette } = useTheme()
|
||||
const { palette } = useTheme();
|
||||
|
||||
// tooltip needs fixing
|
||||
|
||||
const colorScale = React.useMemo(() => {
|
||||
if (countryData?.data) {
|
||||
const heighestNumberOfNodes = Math.max(
|
||||
...Object.values(countryData.data).map((country) => country.nodes)
|
||||
)
|
||||
);
|
||||
return scaleLinear<string, string>()
|
||||
.domain([
|
||||
0,
|
||||
@@ -42,17 +46,17 @@ export const WorldMap: FCWithChildren<MapProps> = ({
|
||||
heighestNumberOfNodes,
|
||||
])
|
||||
.range(palette.nym.networkExplorer.map.fills)
|
||||
.unknown(palette.nym.networkExplorer.map.fills[0])
|
||||
.unknown(palette.nym.networkExplorer.map.fills[0]);
|
||||
}
|
||||
return () => palette.nym.networkExplorer.map.fills[0]
|
||||
}, [countryData, palette])
|
||||
return () => palette.nym.networkExplorer.map.fills[0];
|
||||
}, [countryData, palette]);
|
||||
|
||||
const [tooltipContent, setTooltipContent] = React.useState<string | null>(
|
||||
null
|
||||
)
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return <CircularProgress />
|
||||
return <CircularProgress />;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -61,8 +65,8 @@ export const WorldMap: FCWithChildren<MapProps> = ({
|
||||
data-tip=""
|
||||
style={{
|
||||
backgroundColor: palette.nym.networkExplorer.background.tertiary,
|
||||
width: '100%',
|
||||
height: 'auto',
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
}}
|
||||
viewBox="0, 50, 800, 350"
|
||||
projection="geoMercator"
|
||||
@@ -75,7 +79,7 @@ export const WorldMap: FCWithChildren<MapProps> = ({
|
||||
<Geographies geography={MAP_TOPOJSON}>
|
||||
{({ geographies }) =>
|
||||
geographies.map((geo) => {
|
||||
const d = (countryData?.data || {})[geo.properties.ISO_A3]
|
||||
const d = (countryData?.data || {})[geo.properties.ISO_A3];
|
||||
return (
|
||||
<Geography
|
||||
key={geo.rsmKey}
|
||||
@@ -84,25 +88,25 @@ export const WorldMap: FCWithChildren<MapProps> = ({
|
||||
stroke={palette.nym.networkExplorer.map.stroke}
|
||||
strokeWidth={0.2}
|
||||
onMouseEnter={() => {
|
||||
const { NAME_LONG } = geo.properties
|
||||
const { NAME_LONG } = geo.properties;
|
||||
if (!userLocation) {
|
||||
setTooltipContent(`${NAME_LONG} | ${d?.nodes || 0}`)
|
||||
setTooltipContent(`${NAME_LONG} | ${d?.nodes || 0}`);
|
||||
}
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setTooltipContent('')
|
||||
setTooltipContent("");
|
||||
}}
|
||||
style={{
|
||||
hover:
|
||||
!userLocation && countryData
|
||||
? {
|
||||
fill: palette.nym.highlight,
|
||||
outline: 'white',
|
||||
outline: "white",
|
||||
}
|
||||
: undefined,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
);
|
||||
})
|
||||
}
|
||||
</Geographies>
|
||||
@@ -123,7 +127,7 @@ export const WorldMap: FCWithChildren<MapProps> = ({
|
||||
)}
|
||||
</ZoomableGroup>
|
||||
</ComposableMap>
|
||||
<ReactTooltip>{tooltipContent}</ReactTooltip>
|
||||
<ReactTooltip id="tooltip">{tooltipContent}</ReactTooltip>
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import * as React from 'react'
|
||||
import { PaletteMode } from '@mui/material'
|
||||
import * as React from "react";
|
||||
import { PaletteMode } from "@mui/material";
|
||||
import {
|
||||
ApiState,
|
||||
BlockResponse,
|
||||
@@ -13,110 +13,112 @@ import {
|
||||
ValidatorsResponse,
|
||||
Environment,
|
||||
DirectoryServiceProvider,
|
||||
} from '@/app/typeDefs/explorer-api'
|
||||
import { EnumFilterKey } from '@/app/typeDefs/filters'
|
||||
import { Api, getEnvironment } from '@/app/api'
|
||||
import { toPercentIntegerString } from '@/app/utils'
|
||||
import { NavOptionType, originalNavOptions } from './nav'
|
||||
} from "@/app/typeDefs/explorer-api";
|
||||
import { EnumFilterKey } from "@/app/typeDefs/filters";
|
||||
import { Api, getEnvironment } from "@/app/api";
|
||||
import { toPercentIntegerString } from "@/app/utils";
|
||||
import { NavOptionType, originalNavOptions } from "./nav";
|
||||
|
||||
interface StateData {
|
||||
summaryOverview?: ApiState<SummaryOverviewResponse>
|
||||
block?: ApiState<BlockResponse>
|
||||
countryData?: ApiState<CountryDataResponse>
|
||||
gateways?: ApiState<GatewayResponse>
|
||||
globalError?: string | undefined
|
||||
mixnodes?: ApiState<MixNodeResponse>
|
||||
mode: PaletteMode
|
||||
validators?: ApiState<ValidatorsResponse>
|
||||
environment?: Environment
|
||||
serviceProviders?: ApiState<DirectoryServiceProvider[]>
|
||||
summaryOverview?: ApiState<SummaryOverviewResponse>;
|
||||
block?: ApiState<BlockResponse>;
|
||||
countryData?: ApiState<CountryDataResponse>;
|
||||
gateways?: ApiState<GatewayResponse>;
|
||||
globalError?: string | undefined;
|
||||
mixnodes?: ApiState<MixNodeResponse>;
|
||||
mode: PaletteMode;
|
||||
validators?: ApiState<ValidatorsResponse>;
|
||||
environment?: Environment;
|
||||
serviceProviders?: ApiState<DirectoryServiceProvider[]>;
|
||||
}
|
||||
|
||||
interface StateApi {
|
||||
fetchMixnodes: (
|
||||
status?: MixnodeStatus
|
||||
) => Promise<MixNodeResponse | undefined>
|
||||
filterMixnodes: (filters: any, status: any) => void
|
||||
toggleMode: () => void
|
||||
) => Promise<MixNodeResponse | undefined>;
|
||||
filterMixnodes: (filters: any, status: any) => void;
|
||||
toggleMode: () => void;
|
||||
}
|
||||
|
||||
type State = StateData & StateApi
|
||||
type State = StateData & StateApi;
|
||||
|
||||
export const MainContext = React.createContext<State>({
|
||||
mode: 'dark',
|
||||
mode: "dark",
|
||||
toggleMode: () => undefined,
|
||||
filterMixnodes: () => null,
|
||||
fetchMixnodes: () => Promise.resolve(undefined),
|
||||
})
|
||||
});
|
||||
|
||||
export const useMainContext = (): React.ContextType<typeof MainContext> =>
|
||||
React.useContext<State>(MainContext)
|
||||
React.useContext<State>(MainContext);
|
||||
|
||||
export const MainContextProvider: FCWithChildren = ({ children }) => {
|
||||
export const MainContextProvider: FCWithChildren<{
|
||||
children: React.ReactNode;
|
||||
}> = ({ children }) => {
|
||||
// network explorer environment
|
||||
const [environment, setEnvironment] = React.useState<Environment>()
|
||||
const [environment, setEnvironment] = React.useState<Environment>();
|
||||
|
||||
// light/dark mode
|
||||
const [mode, setMode] = React.useState<PaletteMode>('dark')
|
||||
const [mode, setMode] = React.useState<PaletteMode>("dark");
|
||||
|
||||
// global / banner error messaging
|
||||
const [globalError] = React.useState<string>()
|
||||
const [globalError] = React.useState<string>();
|
||||
|
||||
// various APIs for Overview page
|
||||
const [summaryOverview, setSummaryOverview] =
|
||||
React.useState<ApiState<SummaryOverviewResponse>>()
|
||||
const [mixnodes, setMixnodes] = React.useState<ApiState<MixNodeResponse>>()
|
||||
const [gateways, setGateways] = React.useState<ApiState<GatewayResponse>>()
|
||||
React.useState<ApiState<SummaryOverviewResponse>>();
|
||||
const [mixnodes, setMixnodes] = React.useState<ApiState<MixNodeResponse>>();
|
||||
const [gateways, setGateways] = React.useState<ApiState<GatewayResponse>>();
|
||||
const [validators, setValidators] =
|
||||
React.useState<ApiState<ValidatorsResponse>>()
|
||||
const [block, setBlock] = React.useState<ApiState<BlockResponse>>()
|
||||
React.useState<ApiState<ValidatorsResponse>>();
|
||||
const [block, setBlock] = React.useState<ApiState<BlockResponse>>();
|
||||
const [countryData, setCountryData] =
|
||||
React.useState<ApiState<CountryDataResponse>>()
|
||||
React.useState<ApiState<CountryDataResponse>>();
|
||||
const [serviceProviders, setServiceProviders] =
|
||||
React.useState<ApiState<DirectoryServiceProvider[]>>()
|
||||
React.useState<ApiState<DirectoryServiceProvider[]>>();
|
||||
|
||||
const toggleMode = () => setMode((m) => (m !== 'light' ? 'light' : 'dark'))
|
||||
const toggleMode = () => setMode((m) => (m !== "light" ? "light" : "dark"));
|
||||
|
||||
const fetchOverviewSummary = async () => {
|
||||
try {
|
||||
const data = await Api.fetchOverviewSummary()
|
||||
setSummaryOverview({ data, isLoading: false })
|
||||
const data = await Api.fetchOverviewSummary();
|
||||
setSummaryOverview({ data, isLoading: false });
|
||||
} catch (error) {
|
||||
setSummaryOverview({
|
||||
error:
|
||||
error instanceof Error
|
||||
? error
|
||||
: new Error('Overview summary api fail'),
|
||||
: new Error("Overview summary api fail"),
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const fetchMixnodes = async (status?: MixnodeStatus) => {
|
||||
let data
|
||||
setMixnodes((d) => ({ ...d, isLoading: true }))
|
||||
let data;
|
||||
setMixnodes((d) => ({ ...d, isLoading: true }));
|
||||
try {
|
||||
data = status
|
||||
? await Api.fetchMixnodesActiveSetByStatus(status)
|
||||
: await Api.fetchMixnodes()
|
||||
setMixnodes({ data, isLoading: false })
|
||||
: await Api.fetchMixnodes();
|
||||
setMixnodes({ data, isLoading: false });
|
||||
} catch (error) {
|
||||
setMixnodes({
|
||||
error: error instanceof Error ? error : new Error('Mixnode api fail'),
|
||||
error: error instanceof Error ? error : new Error("Mixnode api fail"),
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
return data
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
const filterMixnodes = async (
|
||||
filters: { [key in EnumFilterKey]: number[] },
|
||||
status?: MixnodeStatus
|
||||
) => {
|
||||
setMixnodes((d) => ({ ...d, isLoading: true }))
|
||||
setMixnodes((d) => ({ ...d, isLoading: true }));
|
||||
const mxns = status
|
||||
? await Api.fetchMixnodesActiveSetByStatus(status)
|
||||
: await Api.fetchMixnodes()
|
||||
: await Api.fetchMixnodes();
|
||||
|
||||
const filtered = mxns?.filter(
|
||||
(m) =>
|
||||
@@ -126,101 +128,101 @@ export const MainContextProvider: FCWithChildren = ({ children }) => {
|
||||
m.stake_saturation <= filters.stakeSaturation[1] &&
|
||||
m.avg_uptime >= filters.routingScore[0] &&
|
||||
m.avg_uptime <= filters.routingScore[1]
|
||||
)
|
||||
);
|
||||
|
||||
setMixnodes({ data: filtered, isLoading: false })
|
||||
}
|
||||
setMixnodes({ data: filtered, isLoading: false });
|
||||
};
|
||||
|
||||
const fetchGateways = async () => {
|
||||
setGateways((d) => ({ ...d, isLoading: true }))
|
||||
setGateways((d) => ({ ...d, isLoading: true }));
|
||||
try {
|
||||
const data = await Api.fetchGateways()
|
||||
setGateways({ data, isLoading: false })
|
||||
const data = await Api.fetchGateways();
|
||||
setGateways({ data, isLoading: false });
|
||||
} catch (error) {
|
||||
setGateways({
|
||||
error: error instanceof Error ? error : new Error('Gateways api fail'),
|
||||
error: error instanceof Error ? error : new Error("Gateways api fail"),
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
const fetchValidators = async () => {
|
||||
try {
|
||||
const data = await Api.fetchValidators()
|
||||
setValidators({ data, isLoading: false })
|
||||
const data = await Api.fetchValidators();
|
||||
setValidators({ data, isLoading: false });
|
||||
} catch (error) {
|
||||
setValidators({
|
||||
error:
|
||||
error instanceof Error ? error : new Error('Validators api fail'),
|
||||
error instanceof Error ? error : new Error("Validators api fail"),
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
const fetchBlock = async () => {
|
||||
try {
|
||||
const data = await Api.fetchBlock()
|
||||
setBlock({ data, isLoading: false })
|
||||
const data = await Api.fetchBlock();
|
||||
setBlock({ data, isLoading: false });
|
||||
} catch (error) {
|
||||
setBlock({
|
||||
error: error instanceof Error ? error : new Error('Block api fail'),
|
||||
error: error instanceof Error ? error : new Error("Block api fail"),
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
const fetchCountryData = async () => {
|
||||
setCountryData({ data: undefined, isLoading: true })
|
||||
setCountryData({ data: undefined, isLoading: true });
|
||||
try {
|
||||
const res = await Api.fetchCountryData()
|
||||
setCountryData({ data: res, isLoading: false })
|
||||
const res = await Api.fetchCountryData();
|
||||
setCountryData({ data: res, isLoading: false });
|
||||
} catch (error) {
|
||||
setCountryData({
|
||||
error:
|
||||
error instanceof Error ? error : new Error('Country Data api fail'),
|
||||
error instanceof Error ? error : new Error("Country Data api fail"),
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const fetchServiceProviders = async () => {
|
||||
setServiceProviders({ data: undefined, isLoading: true })
|
||||
setServiceProviders({ data: undefined, isLoading: true });
|
||||
try {
|
||||
const res = await Api.fetchServiceProviders()
|
||||
const res = await Api.fetchServiceProviders();
|
||||
const resWithRoutingScorePercentage = res.map((item) => ({
|
||||
...item,
|
||||
routing_score: item.routing_score
|
||||
? `${toPercentIntegerString(item.routing_score.toString())}%`
|
||||
: item.routing_score,
|
||||
}))
|
||||
}));
|
||||
setServiceProviders({
|
||||
data: resWithRoutingScorePercentage,
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
} catch (error) {
|
||||
setServiceProviders({
|
||||
error:
|
||||
error instanceof Error
|
||||
? error
|
||||
: new Error('Service provider api fail'),
|
||||
: new Error("Service provider api fail"),
|
||||
isLoading: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (environment === 'mainnet') {
|
||||
fetchServiceProviders()
|
||||
if (environment === "mainnet") {
|
||||
fetchServiceProviders();
|
||||
}
|
||||
}, [environment])
|
||||
}, [environment]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setEnvironment(getEnvironment())
|
||||
setEnvironment(getEnvironment());
|
||||
Promise.all([
|
||||
fetchOverviewSummary(),
|
||||
fetchGateways(),
|
||||
fetchValidators(),
|
||||
fetchBlock(),
|
||||
fetchCountryData(),
|
||||
])
|
||||
}, [])
|
||||
]);
|
||||
}, []);
|
||||
|
||||
const state = React.useMemo<State>(
|
||||
() => ({
|
||||
@@ -250,7 +252,7 @@ export const MainContextProvider: FCWithChildren = ({ children }) => {
|
||||
validators,
|
||||
serviceProviders,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
return <MainContext.Provider value={state}>{children}</MainContext.Provider>
|
||||
}
|
||||
return <MainContext.Provider value={state}>{children}</MainContext.Provider>;
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react'
|
||||
import { FallbackProps } from 'react-error-boundary'
|
||||
import { Alert, AlertTitle, Container } from '@mui/material'
|
||||
import { NymThemeProvider } from '@nymproject/mui-theme'
|
||||
import { NymLogo } from '@nymproject/react/logo/NymLogo'
|
||||
import * as React from "react";
|
||||
import { FallbackProps } from "react-error-boundary";
|
||||
import { Alert, AlertTitle, Container } from "@mui/material";
|
||||
import { NymThemeProvider } from "@nymproject/mui-theme";
|
||||
import { NymLogo } from "@nymproject/react";
|
||||
|
||||
export const ErrorBoundaryContent: FCWithChildren<FallbackProps> = ({
|
||||
error,
|
||||
@@ -15,7 +15,7 @@ export const ErrorBoundaryContent: FCWithChildren<FallbackProps> = ({
|
||||
<AlertTitle>{error.name}</AlertTitle>
|
||||
{error.message}
|
||||
</Alert>
|
||||
{process.env.NODE_ENV === 'development' && (
|
||||
{process.env.NODE_ENV === "development" && (
|
||||
<Alert severity="info" sx={{ mt: 2 }} data-testid="stack-trace">
|
||||
<AlertTitle>Stack trace</AlertTitle>
|
||||
{error.stack}
|
||||
@@ -23,4 +23,4 @@ export const ErrorBoundaryContent: FCWithChildren<FallbackProps> = ({
|
||||
)}
|
||||
</Container>
|
||||
</NymThemeProvider>
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import type { Metadata } from 'next'
|
||||
import '@interchain-ui/react/styles'
|
||||
import { App } from './App'
|
||||
import type { Metadata } from "next";
|
||||
import "@interchain-ui/react/styles";
|
||||
import { App } from "./App";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Nym Network Explorer',
|
||||
}
|
||||
title: "Nym Network Explorer",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode
|
||||
}>) {
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<App>{children}</App>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,106 +1,107 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import React, { useMemo } from 'react'
|
||||
import { Box, Card, Grid, Stack } from '@mui/material'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
import React, { useMemo } from "react";
|
||||
import { Box, Card, Grid, Stack } from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import {
|
||||
MRT_ColumnDef,
|
||||
MaterialReactTable,
|
||||
useMaterialReactTable,
|
||||
} from 'material-react-table'
|
||||
import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid'
|
||||
import { CopyToClipboard } from '@nymproject/react/clipboard/CopyToClipboard'
|
||||
import { Tooltip as InfoTooltip } from '@nymproject/react/tooltip/Tooltip'
|
||||
import { diff, gte, rcompare } from 'semver'
|
||||
import { useMainContext } from '@/app/context/main'
|
||||
import { TableToolbar } from '@/app/components/TableToolbar'
|
||||
import { CustomColumnHeading } from '@/app/components/CustomColumnHeading'
|
||||
import { Title } from '@/app/components/Title'
|
||||
import { unymToNym } from '@/app/utils/currency'
|
||||
import { Tooltip } from '@/app/components/Tooltip'
|
||||
import { NYM_BIG_DIPPER } from '@/app/api/constants'
|
||||
import { splice } from '@/app/utils'
|
||||
} from "material-react-table";
|
||||
import { GridColDef, GridRenderCellParams } from "@mui/x-data-grid";
|
||||
import { CopyToClipboard } from "@nymproject/react";
|
||||
import { Tooltip as InfoTooltip } from "@nymproject/react";
|
||||
import { diff, gte, rcompare } from "semver";
|
||||
import { useMainContext } from "@/app/context/main";
|
||||
import { TableToolbar } from "@/app/components/TableToolbar";
|
||||
import { CustomColumnHeading } from "@/app/components/CustomColumnHeading";
|
||||
import { Title } from "@/app/components/Title";
|
||||
import { unymToNym } from "@/app/utils/currency";
|
||||
import { Tooltip } from "@/app/components/Tooltip";
|
||||
import { NYM_BIG_DIPPER } from "@/app/api/constants";
|
||||
import { splice } from "@/app/utils";
|
||||
import {
|
||||
VersionDisplaySelector,
|
||||
VersionSelectOptions,
|
||||
} from '@/app/components/Gateways/VersionDisplaySelector'
|
||||
import StyledLink from '@/app/components/StyledLink'
|
||||
} from "@/app/components/Gateways/VersionDisplaySelector";
|
||||
import StyledLink from "@/app/components/StyledLink";
|
||||
import {
|
||||
GatewayRowType,
|
||||
gatewayToGridRow,
|
||||
} from '@/app/components/Gateways/Gateways'
|
||||
} from "@/app/components/Gateways/Gateways";
|
||||
import { InfoOutlined } from "@mui/icons-material";
|
||||
|
||||
const PageGateways = () => {
|
||||
const { gateways } = useMainContext()
|
||||
const { gateways } = useMainContext();
|
||||
const [versionFilter, setVersionFilter] =
|
||||
React.useState<VersionSelectOptions>(VersionSelectOptions.all)
|
||||
React.useState<VersionSelectOptions>(VersionSelectOptions.all);
|
||||
|
||||
const theme = useTheme()
|
||||
const theme = useTheme();
|
||||
|
||||
const highestVersion = React.useMemo(() => {
|
||||
if (gateways?.data) {
|
||||
const versions = gateways.data.reduce(
|
||||
(a: string[], b) => [...a, b.gateway.version],
|
||||
[]
|
||||
)
|
||||
const [lastestVersion] = versions.sort(rcompare)
|
||||
return lastestVersion
|
||||
);
|
||||
const [lastestVersion] = versions.sort(rcompare);
|
||||
return lastestVersion;
|
||||
}
|
||||
// fallback value
|
||||
return '2.0.0'
|
||||
}, [gateways])
|
||||
return "2.0.0";
|
||||
}, [gateways]);
|
||||
|
||||
const filterByLatestVersions = React.useMemo(() => {
|
||||
const filtered = gateways?.data?.filter((gw) => {
|
||||
const versionDiff = diff(highestVersion, gw.gateway.version)
|
||||
return versionDiff === 'patch' || versionDiff === null
|
||||
})
|
||||
if (filtered) return filtered
|
||||
return []
|
||||
}, [gateways])
|
||||
const versionDiff = diff(highestVersion, gw.gateway.version);
|
||||
return versionDiff === "patch" || versionDiff === null;
|
||||
});
|
||||
if (filtered) return filtered;
|
||||
return [];
|
||||
}, [gateways]);
|
||||
|
||||
const filterByOlderVersions = React.useMemo(() => {
|
||||
const filtered = gateways?.data?.filter((gw) => {
|
||||
const versionDiff = diff(highestVersion, gw.gateway.version)
|
||||
return versionDiff === 'major' || versionDiff === 'minor'
|
||||
})
|
||||
if (filtered) return filtered
|
||||
return []
|
||||
}, [gateways])
|
||||
const versionDiff = diff(highestVersion, gw.gateway.version);
|
||||
return versionDiff === "major" || versionDiff === "minor";
|
||||
});
|
||||
if (filtered) return filtered;
|
||||
return [];
|
||||
}, [gateways]);
|
||||
|
||||
const filteredByVersion = React.useMemo(() => {
|
||||
switch (versionFilter) {
|
||||
case VersionSelectOptions.latestVersion:
|
||||
return filterByLatestVersions
|
||||
return filterByLatestVersions;
|
||||
case VersionSelectOptions.olderVersions:
|
||||
return filterByOlderVersions
|
||||
return filterByOlderVersions;
|
||||
case VersionSelectOptions.all:
|
||||
return gateways?.data || []
|
||||
return gateways?.data || [];
|
||||
default:
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
}, [versionFilter, gateways])
|
||||
}, [versionFilter, gateways]);
|
||||
|
||||
const data = useMemo(() => {
|
||||
return gatewayToGridRow(filteredByVersion || [])
|
||||
}, [filteredByVersion])
|
||||
return gatewayToGridRow(filteredByVersion || []);
|
||||
}, [filteredByVersion]);
|
||||
|
||||
const columns = useMemo<MRT_ColumnDef<GatewayRowType>[]>(() => {
|
||||
return [
|
||||
{
|
||||
id: 'gateway-data',
|
||||
header: 'Gatewsay Data',
|
||||
id: "gateway-data",
|
||||
header: "Gatewsay Data",
|
||||
columns: [
|
||||
{
|
||||
id: 'identity_key',
|
||||
header: 'Identity Key',
|
||||
accessorKey: 'identity_key',
|
||||
id: "identity_key",
|
||||
header: "Identity Key",
|
||||
accessorKey: "identity_key",
|
||||
size: 250,
|
||||
Cell: ({ row }) => {
|
||||
return (
|
||||
<Stack direction="row" alignItems="center" gap={1}>
|
||||
<CopyToClipboard
|
||||
sx={{ mr: 0.5, color: 'grey.400' }}
|
||||
sx={{ mr: 0.5, color: "grey.400" }}
|
||||
smallIcons
|
||||
value={row.original.identity_key}
|
||||
tooltip={`Copy identity key ${row.original.identity_key} to clipboard`}
|
||||
@@ -113,13 +114,13 @@ const PageGateways = () => {
|
||||
{splice(7, 29, row.original.identity_key)}
|
||||
</StyledLink>
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'node_performance',
|
||||
header: 'Node Performance',
|
||||
accessorKey: 'node_performance',
|
||||
id: "node_performance",
|
||||
header: "Node Performance",
|
||||
accessorKey: "node_performance",
|
||||
size: 200,
|
||||
Header: () => {
|
||||
return (
|
||||
@@ -134,10 +135,13 @@ const PageGateways = () => {
|
||||
}
|
||||
maxWidth={230}
|
||||
arrow
|
||||
TooltipIcon={
|
||||
<InfoOutlined sx={{ width: 18, height: 18, mr: 1 }} />
|
||||
}
|
||||
/>
|
||||
<CustomColumnHeading headingTitle="Routing Score" />
|
||||
</Box>
|
||||
)
|
||||
);
|
||||
},
|
||||
Cell: ({ row }) => {
|
||||
return (
|
||||
@@ -148,13 +152,13 @@ const PageGateways = () => {
|
||||
>
|
||||
{`${row.original.node_performance}%`}
|
||||
</StyledLink>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'version',
|
||||
header: 'Version',
|
||||
accessorKey: 'version',
|
||||
id: "version",
|
||||
header: "Version",
|
||||
accessorKey: "version",
|
||||
size: 150,
|
||||
Cell: ({ row }) => {
|
||||
return (
|
||||
@@ -165,18 +169,18 @@ const PageGateways = () => {
|
||||
>
|
||||
{row.original.version}
|
||||
</StyledLink>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'location',
|
||||
header: 'Location',
|
||||
accessorKey: 'location',
|
||||
id: "location",
|
||||
header: "Location",
|
||||
accessorKey: "location",
|
||||
size: 150,
|
||||
Cell: ({ row }) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{ justifyContent: 'flex-start', cursor: 'pointer' }}
|
||||
sx={{ justifyContent: "flex-start", cursor: "pointer" }}
|
||||
data-testid="location-button"
|
||||
>
|
||||
<Tooltip
|
||||
@@ -185,22 +189,22 @@ const PageGateways = () => {
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
textOverflow: "ellipsis",
|
||||
}}
|
||||
>
|
||||
{row.original.location}
|
||||
</Box>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'host',
|
||||
header: 'IP:Port',
|
||||
accessorKey: 'host',
|
||||
id: "host",
|
||||
header: "IP:Port",
|
||||
accessorKey: "host",
|
||||
size: 150,
|
||||
Cell: ({ row }) => {
|
||||
return (
|
||||
@@ -211,13 +215,13 @@ const PageGateways = () => {
|
||||
>
|
||||
{row.original.host}
|
||||
</StyledLink>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'owner',
|
||||
header: 'Owner',
|
||||
accessorKey: 'owner',
|
||||
id: "owner",
|
||||
header: "Owner",
|
||||
accessorKey: "owner",
|
||||
size: 150,
|
||||
Cell: ({ row }) => {
|
||||
return (
|
||||
@@ -229,18 +233,18 @@ const PageGateways = () => {
|
||||
>
|
||||
{splice(7, 29, row.original.owner)}
|
||||
</StyledLink>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}, [])
|
||||
];
|
||||
}, []);
|
||||
|
||||
const _columns: GridColDef[] = [
|
||||
{
|
||||
field: 'node_performance',
|
||||
align: 'center',
|
||||
field: "node_performance",
|
||||
align: "center",
|
||||
renderHeader: () => (
|
||||
<>
|
||||
<InfoTooltip
|
||||
@@ -251,14 +255,15 @@ const PageGateways = () => {
|
||||
bgColor={theme.palette.nym.networkExplorer.tooltip.background}
|
||||
maxWidth={230}
|
||||
arrow
|
||||
TooltipIcon={<InfoOutlined sx={{ width: 18, height: 18, mr: 1 }} />}
|
||||
/>
|
||||
<CustomColumnHeading headingTitle="Routing Score" />
|
||||
</>
|
||||
),
|
||||
width: 120,
|
||||
disableColumnMenu: true,
|
||||
headerAlign: 'center',
|
||||
headerClassName: 'MuiDataGrid-header-override',
|
||||
headerAlign: "center",
|
||||
headerClassName: "MuiDataGrid-header-override",
|
||||
renderCell: (params: GridRenderCellParams) => (
|
||||
<StyledLink
|
||||
to={`/network-components/gateways/${params.row.identity_key}`}
|
||||
@@ -269,13 +274,13 @@ const PageGateways = () => {
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'version',
|
||||
align: 'center',
|
||||
field: "version",
|
||||
align: "center",
|
||||
renderHeader: () => <CustomColumnHeading headingTitle="Version" />,
|
||||
width: 150,
|
||||
disableColumnMenu: true,
|
||||
headerAlign: 'center',
|
||||
headerClassName: 'MuiDataGrid-header-override',
|
||||
headerAlign: "center",
|
||||
headerClassName: "MuiDataGrid-header-override",
|
||||
renderCell: (params: GridRenderCellParams) => (
|
||||
<StyledLink
|
||||
to={`/network-components/gateways/${params.row.identity_key}`}
|
||||
@@ -285,28 +290,28 @@ const PageGateways = () => {
|
||||
</StyledLink>
|
||||
),
|
||||
sortComparator: (a, b) => {
|
||||
if (gte(a, b)) return 1
|
||||
return -1
|
||||
if (gte(a, b)) return 1;
|
||||
return -1;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'location',
|
||||
field: "location",
|
||||
renderHeader: () => <CustomColumnHeading headingTitle="Location" />,
|
||||
width: 180,
|
||||
disableColumnMenu: true,
|
||||
headerAlign: 'left',
|
||||
headerClassName: 'MuiDataGrid-header-override',
|
||||
headerAlign: "left",
|
||||
headerClassName: "MuiDataGrid-header-override",
|
||||
renderCell: (params: GridRenderCellParams) => (
|
||||
<Box
|
||||
sx={{ justifyContent: 'flex-start', cursor: 'pointer' }}
|
||||
sx={{ justifyContent: "flex-start", cursor: "pointer" }}
|
||||
data-testid="location-button"
|
||||
>
|
||||
<Tooltip text={params.value} id="gateway-location-text">
|
||||
<Box
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
textOverflow: "ellipsis",
|
||||
}}
|
||||
>
|
||||
{params.value}
|
||||
@@ -316,12 +321,12 @@ const PageGateways = () => {
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'host',
|
||||
field: "host",
|
||||
renderHeader: () => <CustomColumnHeading headingTitle="IP:Port" />,
|
||||
width: 180,
|
||||
disableColumnMenu: true,
|
||||
headerAlign: 'left',
|
||||
headerClassName: 'MuiDataGrid-header-override',
|
||||
headerAlign: "left",
|
||||
headerClassName: "MuiDataGrid-header-override",
|
||||
renderCell: (params: GridRenderCellParams) => (
|
||||
<StyledLink
|
||||
to={`/network-components/gateways/${params.row.identity_key}`}
|
||||
@@ -332,13 +337,13 @@ const PageGateways = () => {
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'owner',
|
||||
headerName: 'Owner',
|
||||
field: "owner",
|
||||
headerName: "Owner",
|
||||
renderHeader: () => <CustomColumnHeading headingTitle="Owner" />,
|
||||
width: 180,
|
||||
disableColumnMenu: true,
|
||||
headerAlign: 'left',
|
||||
headerClassName: 'MuiDataGrid-header-override',
|
||||
headerAlign: "left",
|
||||
headerClassName: "MuiDataGrid-header-override",
|
||||
renderCell: (params: GridRenderCellParams) => (
|
||||
<StyledLink
|
||||
to={`${NYM_BIG_DIPPER}/account/${params.value}`}
|
||||
@@ -350,13 +355,13 @@ const PageGateways = () => {
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'bond',
|
||||
field: "bond",
|
||||
width: 150,
|
||||
disableColumnMenu: true,
|
||||
type: 'number',
|
||||
type: "number",
|
||||
renderHeader: () => <CustomColumnHeading headingTitle="Bond" />,
|
||||
headerClassName: 'MuiDataGrid-header-override',
|
||||
headerAlign: 'left',
|
||||
headerClassName: "MuiDataGrid-header-override",
|
||||
headerAlign: "left",
|
||||
renderCell: (params: GridRenderCellParams) => (
|
||||
<StyledLink
|
||||
to={`/network-components/gateways/${params.row.identity_key}`}
|
||||
@@ -366,12 +371,12 @@ const PageGateways = () => {
|
||||
</StyledLink>
|
||||
),
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
const table = useMaterialReactTable({
|
||||
columns,
|
||||
data,
|
||||
})
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -383,7 +388,7 @@ const PageGateways = () => {
|
||||
<Card
|
||||
sx={{
|
||||
padding: 2,
|
||||
height: '100%',
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<TableToolbar
|
||||
@@ -399,7 +404,7 @@ const PageGateways = () => {
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default PageGateways
|
||||
export default PageGateways;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import {
|
||||
MaterialReactTable,
|
||||
useMaterialReactTable,
|
||||
type MRT_ColumnDef,
|
||||
} from 'material-react-table'
|
||||
import { Grid, Card, Button, Box, Stack } from '@mui/material'
|
||||
} from "material-react-table";
|
||||
import { Grid, Card, Button, Box, Stack } from "@mui/material";
|
||||
import {
|
||||
CustomColumnHeading,
|
||||
DelegateIconButton,
|
||||
@@ -21,81 +21,81 @@ import {
|
||||
Title,
|
||||
Tooltip,
|
||||
mixnodeToGridRow,
|
||||
} from '@/app/components'
|
||||
import { DelegationsProvider } from '@/app/context/delegations'
|
||||
import { useWalletContext } from '@/app/context/wallet'
|
||||
import { useGetMixNodeStatusColor, useIsMobile } from '@/app/hooks'
|
||||
import { useMainContext } from '@/app/context/main'
|
||||
import { CopyToClipboard } from '@nymproject/react/clipboard/CopyToClipboard'
|
||||
import { splice } from '@/app/utils'
|
||||
import { currencyToString } from '@/app/utils/currency'
|
||||
import { NYM_BIG_DIPPER } from '@/app/api/constants'
|
||||
} from "@/app/components";
|
||||
import { DelegationsProvider } from "@/app/context/delegations";
|
||||
import { useWalletContext } from "@/app/context/wallet";
|
||||
import { useGetMixNodeStatusColor, useIsMobile } from "@/app/hooks";
|
||||
import { useMainContext } from "@/app/context/main";
|
||||
import { CopyToClipboard } from "@nymproject/react";
|
||||
import { splice } from "@/app/utils";
|
||||
import { currencyToString } from "@/app/utils/currency";
|
||||
import { NYM_BIG_DIPPER } from "@/app/api/constants";
|
||||
import {
|
||||
MixnodeStatusWithAll,
|
||||
toMixnodeStatus,
|
||||
} from '@/app/typeDefs/explorer-api'
|
||||
} from "@/app/typeDefs/explorer-api";
|
||||
|
||||
export default function MixnodesPage() {
|
||||
const isMobile = useIsMobile()
|
||||
const { isWalletConnected } = useWalletContext()
|
||||
const { mixnodes, fetchMixnodes } = useMainContext()
|
||||
const router = useRouter()
|
||||
const isMobile = useIsMobile();
|
||||
const { isWalletConnected } = useWalletContext();
|
||||
const { mixnodes, fetchMixnodes } = useMainContext();
|
||||
const router = useRouter();
|
||||
|
||||
const [itemSelectedForDelegation, setItemSelectedForDelegation] =
|
||||
React.useState<{
|
||||
mixId: number
|
||||
identityKey: string
|
||||
}>()
|
||||
mixId: number;
|
||||
identityKey: string;
|
||||
}>();
|
||||
const [confirmationModalProps, setConfirmationModalProps] = React.useState<
|
||||
DelegationModalProps | undefined
|
||||
>()
|
||||
>();
|
||||
|
||||
const search = useSearchParams()
|
||||
const status = search.get('status') as MixnodeStatusWithAll
|
||||
const search = useSearchParams();
|
||||
const status = search.get("status") as MixnodeStatusWithAll;
|
||||
|
||||
React.useEffect(() => {
|
||||
// when the status changes, get the mixnodes
|
||||
fetchMixnodes(toMixnodeStatus(status))
|
||||
}, [status])
|
||||
fetchMixnodes(toMixnodeStatus(status));
|
||||
}, [status]);
|
||||
|
||||
const handleMixnodeStatusChanged = (newStatus?: MixnodeStatusWithAll) => {
|
||||
router.push(
|
||||
newStatus && newStatus !== 'all'
|
||||
newStatus && newStatus !== "all"
|
||||
? `/network-components/mixnodes?status=${newStatus}`
|
||||
: '/network-components/mixnodes'
|
||||
)
|
||||
}
|
||||
: "/network-components/mixnodes"
|
||||
);
|
||||
};
|
||||
|
||||
const handleOnDelegate = useCallback(
|
||||
({ identityKey, mixId }: { identityKey: string; mixId: number }) => {
|
||||
if (!isWalletConnected) {
|
||||
setConfirmationModalProps({
|
||||
status: 'info',
|
||||
message: 'Please connect your wallet to delegate',
|
||||
})
|
||||
status: "info",
|
||||
message: "Please connect your wallet to delegate",
|
||||
});
|
||||
} else {
|
||||
setItemSelectedForDelegation({ identityKey, mixId })
|
||||
setItemSelectedForDelegation({ identityKey, mixId });
|
||||
}
|
||||
},
|
||||
[isWalletConnected]
|
||||
)
|
||||
);
|
||||
|
||||
const handleNewDelegation = (delegationModalProps: DelegationModalProps) => {
|
||||
setItemSelectedForDelegation(undefined)
|
||||
setConfirmationModalProps(delegationModalProps)
|
||||
}
|
||||
setItemSelectedForDelegation(undefined);
|
||||
setConfirmationModalProps(delegationModalProps);
|
||||
};
|
||||
|
||||
const columns = useMemo<MRT_ColumnDef<MixnodeRowType>[]>(() => {
|
||||
return [
|
||||
{
|
||||
id: 'mixnode-data',
|
||||
header: 'Mixnode Data',
|
||||
id: "mixnode-data",
|
||||
header: "Mixnode Data",
|
||||
columns: [
|
||||
{
|
||||
id: 'delegate',
|
||||
accessorKey: 'delegate',
|
||||
id: "delegate",
|
||||
accessorKey: "delegate",
|
||||
size: isMobile ? 50 : 150,
|
||||
header: '',
|
||||
header: "",
|
||||
grow: false,
|
||||
Cell: ({ row }) => (
|
||||
<DelegateIconButton
|
||||
@@ -113,15 +113,15 @@ export default function MixnodesPage() {
|
||||
Filter: () => null,
|
||||
},
|
||||
{
|
||||
id: 'identity_key',
|
||||
header: 'Identity Key',
|
||||
accessorKey: 'identity_key',
|
||||
id: "identity_key",
|
||||
header: "Identity Key",
|
||||
accessorKey: "identity_key",
|
||||
size: 250,
|
||||
Cell: ({ row }) => {
|
||||
return (
|
||||
<Stack direction="row" alignItems="center" gap={1}>
|
||||
<CopyToClipboard
|
||||
sx={{ mr: 0.5, color: 'grey.400' }}
|
||||
sx={{ mr: 0.5, color: "grey.400" }}
|
||||
smallIcons
|
||||
value={row.original.identity_key}
|
||||
tooltip={`Copy identity key ${row.original.identity_key} to clipboard`}
|
||||
@@ -134,13 +134,13 @@ export default function MixnodesPage() {
|
||||
{splice(7, 29, row.original.identity_key)}
|
||||
</StyledLink>
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'bond',
|
||||
header: 'Stake',
|
||||
accessorKey: 'bond',
|
||||
id: "bond",
|
||||
header: "Stake",
|
||||
accessorKey: "bond",
|
||||
Cell: ({ row }) => (
|
||||
<StyledLink
|
||||
to={`/network-components/mixnodes/${row.original.mix_id}`}
|
||||
@@ -151,9 +151,9 @@ export default function MixnodesPage() {
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'stake_saturation',
|
||||
header: 'Stake Saturation',
|
||||
accessorKey: 'stake_saturation',
|
||||
id: "stake_saturation",
|
||||
header: "Stake Saturation",
|
||||
accessorKey: "stake_saturation",
|
||||
size: 225,
|
||||
Header() {
|
||||
return (
|
||||
@@ -161,7 +161,7 @@ export default function MixnodesPage() {
|
||||
headingTitle="Stake Saturation"
|
||||
tooltipInfo="Level of stake saturation for this node. Nodes receive more rewards the higher their saturation level, up to 100%. Beyond 100% no additional rewards are granted. The current stake saturation level is 940k NYMs, computed as S/K where S is target amount of tokens staked in the network and K is the number of nodes in the reward set."
|
||||
/>
|
||||
)
|
||||
);
|
||||
},
|
||||
Cell: ({ row }) => (
|
||||
<StyledLink
|
||||
@@ -171,9 +171,9 @@ export default function MixnodesPage() {
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'pledge_amount',
|
||||
header: 'Bond',
|
||||
accessorKey: 'pledge_amount',
|
||||
id: "pledge_amount",
|
||||
header: "Bond",
|
||||
accessorKey: "pledge_amount",
|
||||
size: 185,
|
||||
Header: () => (
|
||||
<CustomColumnHeading
|
||||
@@ -193,9 +193,9 @@ export default function MixnodesPage() {
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'profit_percentage',
|
||||
accessorKey: 'profit_percentage',
|
||||
header: 'Profit Margin',
|
||||
id: "profit_percentage",
|
||||
accessorKey: "profit_percentage",
|
||||
header: "Profit Margin",
|
||||
size: 145,
|
||||
Header: () => (
|
||||
<CustomColumnHeading
|
||||
@@ -211,10 +211,10 @@ export default function MixnodesPage() {
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'operating_cost',
|
||||
accessorKey: 'operating_cost',
|
||||
id: "operating_cost",
|
||||
accessorKey: "operating_cost",
|
||||
size: 220,
|
||||
header: 'Operating Cost',
|
||||
header: "Operating Cost",
|
||||
disableColumnMenu: true,
|
||||
Header: () => (
|
||||
<CustomColumnHeading
|
||||
@@ -230,10 +230,10 @@ export default function MixnodesPage() {
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'node_performance',
|
||||
accessorKey: 'node_performance',
|
||||
id: "node_performance",
|
||||
accessorKey: "node_performance",
|
||||
size: 200,
|
||||
header: 'Routing Score',
|
||||
header: "Routing Score",
|
||||
Header: () => (
|
||||
<CustomColumnHeading
|
||||
headingTitle="Routing Score"
|
||||
@@ -248,10 +248,10 @@ export default function MixnodesPage() {
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'owner',
|
||||
accessorKey: 'owner',
|
||||
id: "owner",
|
||||
accessorKey: "owner",
|
||||
size: 150,
|
||||
header: 'Owner',
|
||||
header: "Owner",
|
||||
Header: () => <CustomColumnHeading headingTitle="Owner" />,
|
||||
Cell: ({ row }) => (
|
||||
<StyledLink
|
||||
@@ -265,19 +265,19 @@ export default function MixnodesPage() {
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'location',
|
||||
accessorKey: 'location',
|
||||
header: 'Location',
|
||||
id: "location",
|
||||
accessorKey: "location",
|
||||
header: "Location",
|
||||
maxSize: 150,
|
||||
Header: () => <CustomColumnHeading headingTitle="Location" />,
|
||||
Cell: ({ row }) => (
|
||||
<Tooltip text={row.original.location} id="mixnode-location-text">
|
||||
<Box
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
cursor: 'pointer',
|
||||
overflow: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
textOverflow: "ellipsis",
|
||||
cursor: "pointer",
|
||||
color: useGetMixNodeStatusColor(row.original.status),
|
||||
}}
|
||||
>
|
||||
@@ -287,9 +287,9 @@ export default function MixnodesPage() {
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'host',
|
||||
accessorKey: 'host',
|
||||
header: 'Host',
|
||||
id: "host",
|
||||
accessorKey: "host",
|
||||
header: "Host",
|
||||
size: 130,
|
||||
Header: () => <CustomColumnHeading headingTitle="Host" />,
|
||||
Cell: ({ row }) => (
|
||||
@@ -303,12 +303,12 @@ export default function MixnodesPage() {
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}, [handleOnDelegate, isMobile])
|
||||
];
|
||||
}, [handleOnDelegate, isMobile]);
|
||||
|
||||
const data = useMemo(() => {
|
||||
return mixnodeToGridRow(mixnodes?.data)
|
||||
}, [mixnodes?.data])
|
||||
return mixnodeToGridRow(mixnodes?.data);
|
||||
}, [mixnodes?.data]);
|
||||
|
||||
const table = useMaterialReactTable({
|
||||
columns,
|
||||
@@ -317,11 +317,11 @@ export default function MixnodesPage() {
|
||||
state: {
|
||||
isLoading: mixnodes?.isLoading,
|
||||
},
|
||||
layoutMode: 'grid-no-grow',
|
||||
layoutMode: "grid-no-grow",
|
||||
initialState: {
|
||||
columnPinning: { left: ['delegate'] },
|
||||
columnPinning: { left: ["delegate"] },
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
return (
|
||||
<DelegationsProvider>
|
||||
@@ -333,7 +333,7 @@ export default function MixnodesPage() {
|
||||
<Card
|
||||
sx={{
|
||||
padding: 2,
|
||||
height: '100%',
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<TableToolbar
|
||||
@@ -350,7 +350,7 @@ export default function MixnodesPage() {
|
||||
fullWidth
|
||||
size="large"
|
||||
variant="outlined"
|
||||
onClick={() => router.push('/delegations')}
|
||||
onClick={() => router.push("/delegations")}
|
||||
>
|
||||
Delegations
|
||||
</Button>
|
||||
@@ -364,7 +364,7 @@ export default function MixnodesPage() {
|
||||
{itemSelectedForDelegation && (
|
||||
<DelegateModal
|
||||
onClose={() => {
|
||||
setItemSelectedForDelegation(undefined)
|
||||
setItemSelectedForDelegation(undefined);
|
||||
}}
|
||||
header="Delegate"
|
||||
buttonText="Delegate stake"
|
||||
@@ -382,19 +382,19 @@ export default function MixnodesPage() {
|
||||
{...confirmationModalProps}
|
||||
open={Boolean(confirmationModalProps)}
|
||||
onClose={async () => {
|
||||
setConfirmationModalProps(undefined)
|
||||
if (confirmationModalProps.status === 'success') {
|
||||
router.push('/delegations')
|
||||
setConfirmationModalProps(undefined);
|
||||
if (confirmationModalProps.status === "success") {
|
||||
router.push("/delegations");
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
width: {
|
||||
xs: '90%',
|
||||
xs: "90%",
|
||||
sm: 600,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DelegationsProvider>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import React, { useMemo } from 'react'
|
||||
import React, { useMemo } from "react";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -9,29 +9,28 @@ import {
|
||||
Grid,
|
||||
ListItem,
|
||||
Menu,
|
||||
Typography,
|
||||
} from '@mui/material'
|
||||
import { TableToolbar } from '@/app/components/TableToolbar'
|
||||
import { Title } from '@/app/components/Title'
|
||||
import { useMainContext } from '@/app/context/main'
|
||||
import { CustomColumnHeading } from '@/app/components/CustomColumnHeading'
|
||||
} from "@mui/material";
|
||||
import { TableToolbar } from "@/app/components/TableToolbar";
|
||||
import { Title } from "@/app/components/Title";
|
||||
import { useMainContext } from "@/app/context/main";
|
||||
import { CustomColumnHeading } from "@/app/components/CustomColumnHeading";
|
||||
import {
|
||||
MRT_ColumnDef,
|
||||
MaterialReactTable,
|
||||
useMaterialReactTable,
|
||||
} from 'material-react-table'
|
||||
import { DirectoryServiceProvider } from '@/app/typeDefs/explorer-api'
|
||||
} from "material-react-table";
|
||||
import { DirectoryServiceProvider } from "@/app/typeDefs/explorer-api";
|
||||
|
||||
const SupportedApps = () => {
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null)
|
||||
const open = Boolean(anchorEl)
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const open = Boolean(anchorEl);
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget)
|
||||
}
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null)
|
||||
}
|
||||
const anchorRef = React.useRef<HTMLButtonElement>(null)
|
||||
setAnchorEl(null);
|
||||
};
|
||||
const anchorRef = React.useRef<HTMLButtonElement>(null);
|
||||
|
||||
return (
|
||||
<FormControl size="small">
|
||||
@@ -41,7 +40,7 @@ const SupportedApps = () => {
|
||||
size="large"
|
||||
variant="outlined"
|
||||
color="inherit"
|
||||
sx={{ mr: 2, textTransform: 'capitalize' }}
|
||||
sx={{ mr: 2, textTransform: "capitalize" }}
|
||||
>
|
||||
Supported Apps
|
||||
</Button>
|
||||
@@ -52,67 +51,67 @@ const SupportedApps = () => {
|
||||
<ListItem>Blockstream Green</ListItem>
|
||||
</Menu>
|
||||
</FormControl>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const ServiceProviders = () => {
|
||||
const { serviceProviders } = useMainContext()
|
||||
const { serviceProviders } = useMainContext();
|
||||
|
||||
const columns = useMemo<MRT_ColumnDef<DirectoryServiceProvider>[]>(() => {
|
||||
return [
|
||||
{
|
||||
id: 'service-providers-data',
|
||||
header: 'Service Providers Data',
|
||||
id: "service-providers-data",
|
||||
header: "Service Providers Data",
|
||||
columns: [
|
||||
{
|
||||
id: 'address',
|
||||
accessorKey: 'address',
|
||||
header: 'Client ID',
|
||||
id: "address",
|
||||
accessorKey: "address",
|
||||
header: "Client ID",
|
||||
size: 450,
|
||||
},
|
||||
{
|
||||
id: 'service_type-type',
|
||||
accessorKey: 'service_type',
|
||||
header: 'Type',
|
||||
id: "service_type-type",
|
||||
accessorKey: "service_type",
|
||||
header: "Type",
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
id: 'routing_score-score',
|
||||
accessorKey: 'routing_score',
|
||||
header: 'Routing score',
|
||||
id: "routing_score-score",
|
||||
accessorKey: "routing_score",
|
||||
header: "Routing score",
|
||||
Header() {
|
||||
return (
|
||||
<CustomColumnHeading
|
||||
headingTitle="Routing score"
|
||||
tooltipInfo="Routing score is only displayed for the service providers that had a successful ping within the last two hours"
|
||||
/>
|
||||
)
|
||||
);
|
||||
},
|
||||
Cell({ row }) {
|
||||
return row.original.routing_score || '-'
|
||||
return row.original.routing_score || "-";
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}, [])
|
||||
];
|
||||
}, []);
|
||||
|
||||
const table = useMaterialReactTable({
|
||||
columns,
|
||||
data: serviceProviders?.data || [],
|
||||
layoutMode: 'grid',
|
||||
layoutMode: "grid",
|
||||
state: {
|
||||
isLoading: serviceProviders?.isLoading,
|
||||
},
|
||||
initialState: {
|
||||
sorting: [
|
||||
{
|
||||
id: 'routing_score',
|
||||
id: "routing_score",
|
||||
desc: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -134,7 +133,7 @@ const ServiceProviders = () => {
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default ServiceProviders
|
||||
export default ServiceProviders;
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
|
||||
import React, { useMemo } from 'react'
|
||||
import {
|
||||
Alert,
|
||||
Box,
|
||||
CircularProgress,
|
||||
Grid,
|
||||
SelectChangeEvent,
|
||||
Typography,
|
||||
} from '@mui/material'
|
||||
import { ContentCard } from '@/app/components/ContentCard'
|
||||
import { TableToolbar } from '@/app/components/TableToolbar'
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react'
|
||||
import CosmosKitProvider from '@/app/context/cosmos-kit'
|
||||
import { WalletProvider } from '@/app/context/wallet'
|
||||
import { NetworkExplorerThemeProvider } from '@/app/theme'
|
||||
import { MainContextProvider } from '@/app/context/main'
|
||||
import React from "react";
|
||||
import CosmosKitProvider from "@/app/context/cosmos-kit";
|
||||
import { WalletProvider } from "@/app/context/wallet";
|
||||
import { NetworkExplorerThemeProvider } from "@/app/theme";
|
||||
import { MainContextProvider } from "@/app/context/main";
|
||||
|
||||
const Providers = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
@@ -13,7 +13,7 @@ const Providers = ({ children }: { children: React.ReactNode }) => {
|
||||
</CosmosKitProvider>
|
||||
</NetworkExplorerThemeProvider>
|
||||
</MainContextProvider>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export { Providers }
|
||||
export { Providers };
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import * as React from 'react'
|
||||
import { NymNetworkExplorerThemeProvider } from '@nymproject/mui-theme'
|
||||
import { useMainContext } from '../context/main'
|
||||
import * as React from "react";
|
||||
import { NymNetworkExplorerThemeProvider } from "@nymproject/mui-theme";
|
||||
import { useMainContext } from "../context/main";
|
||||
|
||||
export const NetworkExplorerThemeProvider: FCWithChildren = ({ children }) => {
|
||||
const { mode } = useMainContext()
|
||||
export const NetworkExplorerThemeProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const { mode } = useMainContext();
|
||||
|
||||
return (
|
||||
<NymNetworkExplorerThemeProvider mode={mode}>
|
||||
{children}
|
||||
</NymNetworkExplorerThemeProvider>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
declare type FCWithChildren<P = {}> = React.FC<React.PropsWithChildren<P>>;
|
||||
declare type FCWithChildren<P = object> = React.FC<React.PropsWithChildren<P>>;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
declare module 'react-tooltip';
|
||||
@@ -1,19 +1,21 @@
|
||||
/* eslint-disable camelcase */
|
||||
import { MutableRefObject } from 'react';
|
||||
import { Theme } from '@mui/material/styles';
|
||||
import { registerLocale, getName } from 'i18n-iso-countries';
|
||||
import Big from 'big.js';
|
||||
import { CountryData } from '@/app/typeDefs/explorer-api';
|
||||
import { EconomicsRowsType } from '@/app/components/MixNodes/Economics/types';
|
||||
import { Network } from '../typeDefs/network';
|
||||
import { MutableRefObject } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { registerLocale, getName } from "i18n-iso-countries";
|
||||
import Big from "big.js";
|
||||
import { CountryData } from "@/app/typeDefs/explorer-api";
|
||||
import { EconomicsRowsType } from "@/app/components/MixNodes/Economics/types";
|
||||
import { Network } from "../typeDefs/network";
|
||||
|
||||
registerLocale(require('i18n-iso-countries/langs/en.json'));
|
||||
registerLocale(require("i18n-iso-countries/langs/en.json"));
|
||||
|
||||
export function formatNumber(num: number): string {
|
||||
return new Intl.NumberFormat().format(num);
|
||||
}
|
||||
|
||||
export function scrollToRef(ref: MutableRefObject<HTMLDivElement | undefined>): void {
|
||||
export function scrollToRef(
|
||||
ref: MutableRefObject<HTMLDivElement | undefined>
|
||||
): void {
|
||||
if (ref?.current) ref.current.scrollIntoView();
|
||||
}
|
||||
|
||||
@@ -25,13 +27,15 @@ export type CountryDataRowType = {
|
||||
percentage: string;
|
||||
};
|
||||
|
||||
export function countryDataToGridRow(countriesData: CountryData[]): CountryDataRowType[] {
|
||||
export function countryDataToGridRow(
|
||||
countriesData: CountryData[]
|
||||
): CountryDataRowType[] {
|
||||
const totalNodes = countriesData.reduce((acc, obj) => acc + obj.nodes, 0);
|
||||
const formatted = countriesData.map((each: CountryData, index: number) => {
|
||||
const updatedCountryRecord: CountryDataRowType = {
|
||||
...each,
|
||||
id: index,
|
||||
countryName: getName(each.ISO3, 'en', { select: 'alias' }),
|
||||
countryName: getName(each.ISO3, "en", { select: "alias" }) || "",
|
||||
percentage: ((each.nodes * 100) / totalNodes).toFixed(1),
|
||||
};
|
||||
return updatedCountryRecord;
|
||||
@@ -41,16 +45,21 @@ export function countryDataToGridRow(countriesData: CountryData[]): CountryDataR
|
||||
return sorted;
|
||||
}
|
||||
|
||||
export const splice = (start: number, deleteCount: number, address?: string): string => {
|
||||
export const splice = (
|
||||
start: number,
|
||||
deleteCount: number,
|
||||
address?: string
|
||||
): string => {
|
||||
if (address) {
|
||||
const array = address.split('');
|
||||
array.splice(start, deleteCount, '...');
|
||||
return array.join('');
|
||||
const array = address.split("");
|
||||
array.splice(start, deleteCount, "...");
|
||||
return array.join("");
|
||||
}
|
||||
return '';
|
||||
return "";
|
||||
};
|
||||
|
||||
export const trimAddress = (address = '', trimBy = 6) => `${address.slice(0, trimBy)}...${address.slice(-trimBy)}`;
|
||||
export const trimAddress = (address = "", trimBy = 6) =>
|
||||
`${address.slice(0, trimBy)}...${address.slice(-trimBy)}`;
|
||||
|
||||
/**
|
||||
* Converts a stringified percentage float (0.0-1.0) to a stringified integer (0-100).
|
||||
@@ -58,27 +67,33 @@ export const trimAddress = (address = '', trimBy = 6) => `${address.slice(0, tri
|
||||
* @param value - the percentage to convert
|
||||
* @returns A stringified integer
|
||||
*/
|
||||
export const toPercentIntegerString = (value: string) => Math.round(Number(value) * 100).toString();
|
||||
export const toPercentInteger = (value: string) => Math.round(Number(value) * 100);
|
||||
export const toPercentIntegerString = (value: string) =>
|
||||
Math.round(Number(value) * 100).toString();
|
||||
export const toPercentInteger = (value: string) =>
|
||||
Math.round(Number(value) * 100);
|
||||
|
||||
export const textColour = (value: EconomicsRowsType, field: string, theme: Theme) => {
|
||||
export const textColour = (
|
||||
value: EconomicsRowsType,
|
||||
field: string,
|
||||
theme: Theme
|
||||
) => {
|
||||
const progressBarValue = value?.progressBarValue || 0;
|
||||
const fieldValue = value.value;
|
||||
|
||||
if (progressBarValue > 100) {
|
||||
return theme.palette.warning.main;
|
||||
}
|
||||
if (field === 'selectionChance') {
|
||||
if (field === "selectionChance") {
|
||||
// TODO: when v2 will be deployed, remove cases: VeryHigh, Moderate and VeryLow
|
||||
switch (fieldValue) {
|
||||
case 'High':
|
||||
case 'VeryHigh':
|
||||
case "High":
|
||||
case "VeryHigh":
|
||||
return theme.palette.nym.networkExplorer.selectionChance.overModerate;
|
||||
case 'Good':
|
||||
case 'Moderate':
|
||||
case "Good":
|
||||
case "Moderate":
|
||||
return theme.palette.nym.networkExplorer.selectionChance.moderate;
|
||||
case 'Low':
|
||||
case 'VeryLow':
|
||||
case "Low":
|
||||
case "VeryLow":
|
||||
return theme.palette.nym.networkExplorer.selectionChance.underModerate;
|
||||
default:
|
||||
return theme.palette.nym.wallet.fee;
|
||||
@@ -101,8 +116,12 @@ export const isLessThan = (a: number, b: number) => a < b;
|
||||
*
|
||||
*/
|
||||
|
||||
export const isBalanceEnough = (fee: string, tx: string = '0', balance: string = '0') => {
|
||||
console.log('balance', balance, fee, tx);
|
||||
export const isBalanceEnough = (
|
||||
fee: string,
|
||||
tx: string = "0",
|
||||
balance: string = "0"
|
||||
) => {
|
||||
console.log("balance", balance, fee, tx);
|
||||
try {
|
||||
return Big(balance).gte(Big(fee).plus(Big(tx)));
|
||||
} catch (e) {
|
||||
@@ -112,13 +131,13 @@ export const isBalanceEnough = (fee: string, tx: string = '0', balance: string =
|
||||
};
|
||||
|
||||
export const urls = (networkName?: Network) =>
|
||||
networkName === 'MAINNET'
|
||||
networkName === "MAINNET"
|
||||
? {
|
||||
mixnetExplorer: 'https://mixnet.explorers.guru/',
|
||||
blockExplorer: 'https://blocks.nymtech.net',
|
||||
networkExplorer: 'https://explorer.nymtech.net',
|
||||
}
|
||||
mixnetExplorer: "https://mixnet.explorers.guru/",
|
||||
blockExplorer: "https://blocks.nymtech.net",
|
||||
networkExplorer: "https://explorer.nymtech.net",
|
||||
}
|
||||
: {
|
||||
blockExplorer: `https://${networkName}-blocks.nymtech.net`,
|
||||
networkExplorer: `https://${networkName}-explorer.nymtech.net`,
|
||||
};
|
||||
blockExplorer: `https://${networkName}-blocks.nymtech.net`,
|
||||
networkExplorer: `https://${networkName}-explorer.nymtech.net`,
|
||||
};
|
||||
|
||||
@@ -4,25 +4,56 @@
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"build:prod": "yarn --cwd .. build && next build",
|
||||
"build:prod": "pnpm i && pnpm -C .. build && next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nymproject/react": "^1.0.0",
|
||||
"@nymproject/nym-validator-client": "0.18.0",
|
||||
"@chain-registry/types": "^0.45.9",
|
||||
"@cosmjs/cosmwasm-stargate": "^0.29.5",
|
||||
"@cosmos-kit/core": "^2.13.1",
|
||||
"@cosmos-kit/keplr-extension": "^2.12.2",
|
||||
"@cosmos-kit/react": "^2.17.2",
|
||||
"@mui/base": "5.0.0-beta.40",
|
||||
"@mui/icons-material": "^5.2.0",
|
||||
"@mui/material": "^5.2.2",
|
||||
"@mui/styles": "^5.2.2",
|
||||
"@mui/system": "^5.15.20",
|
||||
"@mui/x-data-grid": "7.1.1",
|
||||
"@mui/x-date-pickers": "7.1.1",
|
||||
"@nymproject/contract-clients": "1.2.4-rc.1",
|
||||
"@nymproject/mui-theme": "workspace:^1.0.0",
|
||||
"@nymproject/nym-validator-client": "^0.18.0",
|
||||
"@nymproject/react": "workspace:^1.0.0",
|
||||
"@nymproject/types": "workspace:^1.0.0",
|
||||
"@storybook/react": "^6.5.15",
|
||||
"@types/d3-scale": "^4.0.8",
|
||||
"big.js": "^6.2.1",
|
||||
"chain-registry": "^1.63.12",
|
||||
"d3-scale": "^4.0.2",
|
||||
"date-fns": "^2.28.0",
|
||||
"i18n-iso-countries": "^7.11.2",
|
||||
"lodash": "^4.17.21",
|
||||
"material-react-table": "^2.12.1",
|
||||
"next": "14.1.4",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-error-boundary": "^4.0.13",
|
||||
"material-react-table": "^2.12.1",
|
||||
"@mui/x-date-pickers": "7.1.1",
|
||||
"@mui/x-data-grid": "7.1.1"
|
||||
"react-google-charts": "^4.0.1",
|
||||
"react-identicons": "^1.2.5",
|
||||
"react-simple-maps": "^3.0.0",
|
||||
"react-tooltip": "^5.27.0",
|
||||
"semver": "^6.3.1",
|
||||
"use-clipboard-copy": "^0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/big.js": "^6.1.6",
|
||||
"@types/lodash": "^4.17.6",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"@types/react-simple-maps": "^3.0.4",
|
||||
"@types/semver": "^7.3.8",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.1.4",
|
||||
"typescript": "^5"
|
||||
|
||||
@@ -40,11 +40,11 @@
|
||||
"@mui/system": "^5.0.1",
|
||||
"@mui/x-data-grid": "^5.0.0-beta.5",
|
||||
"@nymproject/contract-clients": "1.2.4-rc.1",
|
||||
"@nymproject/mui-theme": "^1.0.0",
|
||||
"@nymproject/mui-theme": "workspace: ^1.0.0",
|
||||
"@nymproject/node-tester": "^1.0.0",
|
||||
"@nymproject/nym-validator-client": "^0.18.0",
|
||||
"@nymproject/react": "^1.0.0",
|
||||
"@nymproject/types": "^1.0.0",
|
||||
"@nymproject/react": "workspace:^1.0.0",
|
||||
"@nymproject/types": "workspace:^1.0.0",
|
||||
"@tauri-apps/api": "^1.5.1",
|
||||
"big.js": "^6.2.1",
|
||||
"bs58": "^5.0.0",
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@nymproject/eslint-config-react-typescript": "workspace:^1.0.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
|
||||
"@storybook/addon-actions": "^6.5.8",
|
||||
"@storybook/addon-essentials": "^6.5.8",
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"version": "independent"
|
||||
}
|
||||
@@ -36,7 +36,7 @@
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@nymproject/eslint-config-react-typescript": "workspace:^1.0.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
|
||||
"@svgr/webpack": "^6.1.1",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
|
||||
@@ -12,7 +12,7 @@ serde_json = "1.0"
|
||||
strum = { version = "0.23", features = ["derive"] }
|
||||
ts-rs = "7.0.0"
|
||||
|
||||
cosmwasm-std = "1.4.3"
|
||||
cosmwasm-std = "1.3.0"
|
||||
cosmrs = "=0.15.0"
|
||||
|
||||
nym-config = { path = "../../common/config" }
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cosmwasm_std::Coin;
|
||||
use nym_mixnet_contract_common::{
|
||||
ContractStateParams, OperatingCostRange as ContractOperatingCostRange,
|
||||
ProfitMarginRange as ContractProfitMarginRange,
|
||||
};
|
||||
use nym_mixnet_contract_common::ContractStateParams;
|
||||
use nym_types::currency::{DecCoin, RegisteredCoins};
|
||||
use nym_types::error::TypesError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -20,31 +16,6 @@ pub struct TauriContractStateParams {
|
||||
minimum_mixnode_pledge: DecCoin,
|
||||
minimum_gateway_pledge: DecCoin,
|
||||
minimum_mixnode_delegation: Option<DecCoin>,
|
||||
|
||||
operating_cost: TauriOperatingCostRange,
|
||||
profit_margin: TauriProfitMarginRange,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "nym-wallet/src/types/rust/OperatingCostRange.ts")
|
||||
)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct TauriOperatingCostRange {
|
||||
minimum: DecCoin,
|
||||
maximum: DecCoin,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "nym-wallet/src/types/rust/ProfitMarginRange.ts")
|
||||
)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct TauriProfitMarginRange {
|
||||
minimum: String,
|
||||
maximum: String,
|
||||
}
|
||||
|
||||
impl TauriContractStateParams {
|
||||
@@ -52,16 +23,6 @@ impl TauriContractStateParams {
|
||||
state_params: ContractStateParams,
|
||||
reg: &RegisteredCoins,
|
||||
) -> Result<Self, TypesError> {
|
||||
let rewarding_denom = &state_params.minimum_mixnode_pledge.denom;
|
||||
let min_operating_cost_c = Coin {
|
||||
denom: rewarding_denom.into(),
|
||||
amount: state_params.interval_operating_cost.minimum,
|
||||
};
|
||||
let max_operating_cost_c = Coin {
|
||||
denom: rewarding_denom.into(),
|
||||
amount: state_params.interval_operating_cost.maximum,
|
||||
};
|
||||
|
||||
Ok(TauriContractStateParams {
|
||||
minimum_mixnode_pledge: reg
|
||||
.attempt_convert_to_display_dec_coin(state_params.minimum_mixnode_pledge.into())?,
|
||||
@@ -71,15 +32,6 @@ impl TauriContractStateParams {
|
||||
.minimum_mixnode_delegation
|
||||
.map(|min_del| reg.attempt_convert_to_display_dec_coin(min_del.into()))
|
||||
.transpose()?,
|
||||
|
||||
operating_cost: TauriOperatingCostRange {
|
||||
minimum: reg.attempt_convert_to_display_dec_coin(min_operating_cost_c.into())?,
|
||||
maximum: reg.attempt_convert_to_display_dec_coin(max_operating_cost_c.into())?,
|
||||
},
|
||||
profit_margin: TauriProfitMarginRange {
|
||||
minimum: state_params.profit_margin.minimum.to_string(),
|
||||
maximum: state_params.profit_margin.maximum.to_string(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -87,14 +39,6 @@ impl TauriContractStateParams {
|
||||
self,
|
||||
reg: &RegisteredCoins,
|
||||
) -> Result<ContractStateParams, TypesError> {
|
||||
assert_eq!(
|
||||
self.operating_cost.maximum.denom,
|
||||
self.operating_cost.minimum.denom
|
||||
);
|
||||
|
||||
let min_operating_cost_c = reg.attempt_convert_to_base_coin(self.operating_cost.minimum)?;
|
||||
let max_operating_cost_c = reg.attempt_convert_to_base_coin(self.operating_cost.maximum)?;
|
||||
|
||||
Ok(ContractStateParams {
|
||||
minimum_mixnode_delegation: self
|
||||
.minimum_mixnode_delegation
|
||||
@@ -107,15 +51,6 @@ impl TauriContractStateParams {
|
||||
minimum_gateway_pledge: reg
|
||||
.attempt_convert_to_base_coin(self.minimum_gateway_pledge)?
|
||||
.into(),
|
||||
|
||||
profit_margin: ContractProfitMarginRange {
|
||||
minimum: self.profit_margin.minimum.parse()?,
|
||||
maximum: self.profit_margin.maximum.parse()?,
|
||||
},
|
||||
interval_operating_cost: ContractOperatingCostRange {
|
||||
minimum: min_operating_cost_c.amount.into(),
|
||||
maximum: max_operating_cost_c.amount.into(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+16
-15
@@ -5,20 +5,20 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "run-s webpack:prod tauri:build",
|
||||
"dev": "run-p tauri:dev webpack:dev",
|
||||
"dev": "pnpm run-p tauri:dev webpack:dev",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"prebuild": "yarn --cwd .. build",
|
||||
"prestorybook": "yarn --cwd .. build",
|
||||
"prewebpack:dev": "yarn --cwd .. build",
|
||||
"prebuild": "pnpm -C .. build",
|
||||
"prestorybook": "pnpm -C .. build",
|
||||
"prewebpack:dev": "pnpm -C .. run build",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"storybook:build": "build-storybook",
|
||||
"tauri:build": "yarn tauri build",
|
||||
"tauri:dev": "yarn tauri dev",
|
||||
"tauri:build": "pnpm tauri build",
|
||||
"tauri:dev": "pnpm tauri dev",
|
||||
"tsc": "tsc --noEmit true",
|
||||
"tsc:watch": "tsc --noEmit true --watch",
|
||||
"webpack:dev": "yarn webpack serve --config webpack.dev.js",
|
||||
"webpack:prod": "yarn webpack --progress --config webpack.prod.js"
|
||||
"webpack:dev": "pnpm webpack serve --config webpack.dev.js",
|
||||
"webpack:prod": "pnpm webpack --progress --config webpack.prod.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.7.0",
|
||||
@@ -28,10 +28,11 @@
|
||||
"@mui/material": "^5.2.2",
|
||||
"@mui/styles": "^5.2.2",
|
||||
"@mui/utils": "^5.7.0",
|
||||
"@nymproject/mui-theme": "^1.0.0",
|
||||
"@nymproject/node-tester": "^1.2.3",
|
||||
"@nymproject/react": "^1.0.0",
|
||||
"@nymproject/types": "^1.0.0",
|
||||
"@nymproject/mui-theme": "workspace:^1.0.0",
|
||||
"@nymproject/node-tester": "1.2.4-rc.1",
|
||||
"@nymproject/react": "workspace:^1.0.0",
|
||||
"@nymproject/types": "workspace:^1.0.0",
|
||||
"@nymproject/webpack": "workspace:^1.0.0",
|
||||
"@storybook/react": "^6.5.15",
|
||||
"@tauri-apps/api": "^1.2.0",
|
||||
"@tauri-apps/tauri-forage": "^1.0.0-beta.2",
|
||||
@@ -42,7 +43,6 @@
|
||||
"joi": "^17.11.0",
|
||||
"lodash": "^4.17.21",
|
||||
"notistack": "^2.0.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"qrcode.react": "^1.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@@ -63,7 +63,7 @@
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@nymproject/eslint-config-react-typescript": "workspace:^1.0.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
|
||||
"@storybook/react": "^6.5.15",
|
||||
"@svgr/webpack": "^6.1.1",
|
||||
@@ -73,6 +73,7 @@
|
||||
"@types/big.js": "^6.1.6",
|
||||
"@types/bs58": "^4.0.1",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/lodash": "^4.17.6",
|
||||
"@types/node": "^16.7.13",
|
||||
"@types/qrcode.react": "^1.0.2",
|
||||
"@types/react": "^18.0.26",
|
||||
@@ -125,4 +126,4 @@
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"private": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { ComponentMeta } from '@storybook/react';
|
||||
import { Playground } from '@nymproject/react/playground/Playground';
|
||||
|
||||
export default {
|
||||
title: 'Playground',
|
||||
component: Playground,
|
||||
} as ComponentMeta<typeof Playground>;
|
||||
|
||||
export const AllControls = () => <Playground />;
|
||||
+37
-34
@@ -3,55 +3,58 @@
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"license": "Apache 2.0",
|
||||
"workspaces": [
|
||||
"dist/wasm/**",
|
||||
"dist/node/**",
|
||||
"dist/ts/**",
|
||||
"sdk/typescript/packages/mui-theme",
|
||||
"sdk/typescript/packages/react-components",
|
||||
"sdk/typescript/packages/validator-client",
|
||||
"ts-packages/*",
|
||||
"nym-wallet",
|
||||
"explorer",
|
||||
"explorer-nextjs",
|
||||
"types",
|
||||
"clients/validator"
|
||||
],
|
||||
"scripts": {
|
||||
"nuke": "npx rimraf **/node_modules node_modules",
|
||||
"scrub": "npx rimraf **/dist dist",
|
||||
"clean": "lerna run clean",
|
||||
"build": "run-s build:types build:packages",
|
||||
"build": "pnpm build:types && pnpm build:packages",
|
||||
"build:wasm": "make sdk-wasm-build",
|
||||
"build:types": "lerna run --scope @nymproject/types build --stream",
|
||||
"build:types": "pnpm run --filter @nymproject/types --stream build",
|
||||
"build:packages": "run-s build:packages:theme build:packages:react",
|
||||
"build:packages:theme": "lerna run --scope @nymproject/mui-theme build",
|
||||
"build:packages:react": "lerna run --scope @nymproject/react build",
|
||||
"build:react-example": "lerna run --scope @nymproject/react-webpack-with-theme-example build --stream",
|
||||
"build:playground": "lerna run --scope @nymproject/react storybook:build --stream",
|
||||
"build:ci:storybook": "yarn build && yarn dev:on && run-p build:react-example build:playground && yarn build:ci:storybook:collect-artifacts",
|
||||
"build:packages:theme": "pnpm run --filter @nymproject/mui-theme build",
|
||||
"build:packages:react": "pnpm run --filter @nymproject/react build",
|
||||
"build:react-example": "pnpm run --filter @nymproject/react-webpack-with-theme-example --stream build ",
|
||||
"build:playground": "pnpm run --filter @nymproject/react --stream storybook:build",
|
||||
"build:ci:storybook": "pnpm run build && pnpm run dev:on && run-p build:react-example build:playground && pnpm build:ci:storybook:collect-artifacts",
|
||||
"build:ci:storybook:collect-artifacts": "mkdir -p ts-packages/dist && mv sdk/typescript/packages/react-components/storybook-static ts-packages/dist/storybook && mv sdk/typescript/examples/react/mui-theme/dist ts-packages/dist/example",
|
||||
"prebuild:ci": "yarn dev:on && yarn",
|
||||
"build:ci": "run-s build:types build:packages build:wasm build:ci:sdk",
|
||||
"postbuild:ci": "yarn dev:off",
|
||||
"build:ci:sdk": "lerna run --scope '{@nymproject/sdk,@nymproject/node-tester,@nymproject/contract-clients,@nymproject/sdk-react,@nymproject/mix-fetch,@nymproject/nodejs-client,@nymproject/mix-fetch-node}' build --stream",
|
||||
"docs:prod:build": "run-s docs:prod:build:ws",
|
||||
"docs:prod:build:ws": "lerna run docs:prod:build --stream",
|
||||
"prebuild:ci": "pnpm run dev:on",
|
||||
"build:ci": "pnpm dlx npm-run-all build:types build:packages build:wasm build:ci:sdk",
|
||||
"postbuild:ci": "pnpm run dev:off",
|
||||
"build:ci:sdk": "pnpm run --filter '{@nymproject/sdk,@nymproject/node-tester,@nymproject/contract-clients,@nymproject/sdk-react,@nymproject/mix-fetch,@nymproject/nodejs-client,@nymproject/mix-fetch-node}' --stream build",
|
||||
"docs:prod:build": "pnpm docs:prod:build:ws",
|
||||
"docs:prod:build:ws": "pnpm -r docs:prod:build",
|
||||
"sdk:build": "./sdk/typescript/scripts/build-prod-sdk.sh",
|
||||
"sdk:publish": "./sdk/typescript/scripts/publish.sh",
|
||||
"lint": "lerna run lint --stream",
|
||||
"lint:fix": "lerna run lint:fix --stream",
|
||||
"tsc": "lerna run tsc --stream",
|
||||
"types:lint:fix": "lerna run lint:fix --scope @nymproject/types --scope @nymproject/nym-wallet-app",
|
||||
"lint": "pnpm -r run --stream lint",
|
||||
"lint:fix": "pnpm -r run --stream lint:fix",
|
||||
"tsc": "pnpm -r run --stream tsc",
|
||||
"types:lint:fix": "pnpm run lint:fix --filter @nymproject/types --filter @nymproject/nym-wallet-app",
|
||||
"audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run",
|
||||
"dev:on": "node sdk/typescript/scripts/dev-mode-add.mjs",
|
||||
"dev:off": "node sdk/typescript/scripts/dev-mode-remove.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lerna": "^7.3.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"@npmcli/node-gyp": "^3.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"node-gyp": "^9.3.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"tslog": "3.3.3"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"d3-color@<3.1.0": ">=3.1.0",
|
||||
"trim@<0.0.3": ">=0.0.3",
|
||||
"sharp@<0.30.5": ">=0.30.5",
|
||||
"postcss@<8.4.31": ">=8.4.31",
|
||||
"sharp@<0.32.6": ">=0.32.6",
|
||||
"trim-newlines@<3.0.1": ">=3.0.1",
|
||||
"semver@>=7.0.0 <7.5.2": ">=7.5.2",
|
||||
"xml2js@<0.5.0": ">=0.5.0",
|
||||
"webpack-dev-middleware@<=5.3.3": ">=5.3.4",
|
||||
"@babel/traverse@<7.23.2": ">=7.23.2",
|
||||
"ws@>=8.0.0 <8.17.1": ">=8.17.1",
|
||||
"axios@>=0.8.1 <0.28.0": ">=0.28.0",
|
||||
"protobufjs@>=6.10.0 <6.11.4": ">=6.11.4",
|
||||
"braces@<3.0.3": ">=3.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+39228
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
packages:
|
||||
- clients/validator
|
||||
- dist/wasm/**
|
||||
- dist/node/**
|
||||
- dist/ts/**
|
||||
- explorer-nextjs
|
||||
- sdk/typescript/packages/react-components
|
||||
- sdk/typescript/packages/validator-client
|
||||
- sdk/typescript/packages/mui-theme
|
||||
- sdk/typescript/packages/**
|
||||
- sdk/typescript/examples/**
|
||||
- sdk/typescript/codegen/**
|
||||
- ts-packages/**
|
||||
- wallet
|
||||
@@ -15,7 +15,7 @@
|
||||
"docs:generate:prod": "typedoc --basePath ./docs/tsdoc/nymproject/contract-clients/",
|
||||
"docs:prod:build": "scripts/build-prod-docs-collect.sh",
|
||||
"docs:serve": "reload -b -d ./docs -p 3000",
|
||||
"docs:watch": "nodemon --ext ts --watch './src/**/*' --watch './typedoc.json' --exec \"yarn docs:generate\""
|
||||
"docs:watch": "nodemon --ext ts --watch './src/**/*' --watch './typedoc.json' --exec \"pnpm docs:generate\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cosmwasm/ts-codegen": "^0.35.3",
|
||||
@@ -26,5 +26,9 @@
|
||||
"typescript": "^4.6.2"
|
||||
},
|
||||
"private": false,
|
||||
"types": "./dist/index.d.ts"
|
||||
}
|
||||
"types": "./dist/index.d.ts",
|
||||
"dependencies": {
|
||||
"@cosmjs/amino": "^0.32.4",
|
||||
"@cosmjs/cosmwasm-stargate": "^0.29.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ set -o pipefail
|
||||
rm -rf ../../../../dist/ts/docs/tsdoc/nymproject/contract-clients || true
|
||||
|
||||
# run the build
|
||||
yarn docs:generate:prod
|
||||
pnpm docs:generate:prod
|
||||
|
||||
# move the output outside of the yarn/npm workspaces
|
||||
mkdir -p ../../../../dist/ts/docs/tsdoc/nymproject
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"build": "npx parcel build",
|
||||
"build:serve": "npx serve dist",
|
||||
"lint": "eslint src",
|
||||
"lint": "echo not implemented",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"start": "npx parcel",
|
||||
"test": "jest",
|
||||
@@ -41,4 +41,4 @@
|
||||
"private": false,
|
||||
"browserslist": "> 0.5%, last 2 versions, not dead",
|
||||
"source": "src/index.html"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
"build": "webpack build --progress --config webpack.prod.js",
|
||||
"build:dev": "webpack build --progress",
|
||||
"build:serve": "npx serve dist",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"lint": "echo not implemented",
|
||||
"start": "webpack serve --progress --port 3000",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
@@ -62,4 +61,4 @@
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"private": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"description": "An example project that uses WASM, React, Webpack, Typescript and the Nym theme + components library",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"build": "webpack build --progress --config webpack.prod.js",
|
||||
"build": "echo not implemented",
|
||||
"build:dev": "webpack build --progress",
|
||||
"build:serve": "npx serve dist",
|
||||
"lint": "eslint src",
|
||||
@@ -78,7 +78,7 @@
|
||||
"typescript": "^4.6.2",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-cli": "^5.1.4",
|
||||
"webpack-dev-server": "^4.5.0",
|
||||
"webpack-favicons": "^1.3.8",
|
||||
"webpack-merge": "^5.8.0"
|
||||
@@ -90,4 +90,4 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -1,5 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { createNymMixnetClient, IWebWorkerEvents, MimeTypes, NymClientConfig, NymMixnetClient } from '@nymproject/sdk';
|
||||
|
||||
export interface BinaryMessageHeaders {
|
||||
filename: string;
|
||||
mimeType: string;
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { App } from './App';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('app'));
|
||||
const element = document.getElementById('app');
|
||||
|
||||
if (!element) {
|
||||
throw new Error('Element not found');
|
||||
}
|
||||
|
||||
createRoot(element).render(<App />);
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
"version": "1.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"@mui/material": "^5.0.1",
|
||||
"@mui/styles": "^5.0.1",
|
||||
"@mui/icons-material": "^5.5.0",
|
||||
"@mui/lab": "^5.0.0-alpha.72",
|
||||
"@nymproject/mui-theme": "^1.0.0",
|
||||
"@nymproject/react": "^1.0.0"
|
||||
"@mui/material": "^5.0.1",
|
||||
"@mui/styles": "^5.0.1",
|
||||
"@nymproject/mui-theme": "workspace:^1.0.0",
|
||||
"@nymproject/react": "workspace:^1.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
@@ -19,15 +19,16 @@
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@nymproject/webpack": "^1.0.0",
|
||||
"@nymproject/eslint-config-react-typescript": "workspace:^1.0.0",
|
||||
"@nymproject/webpack": "workspace:^1.0.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
|
||||
"@svgr/webpack": "^6.1.1",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/node": "^16.7.13",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||
"@typescript-eslint/parser": "^5.13.0",
|
||||
"babel-loader": "^8.3.0",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { Box, Container, Grid, Typography } from '@mui/material';
|
||||
import { NymLogo } from '@nymproject/react/logo/NymLogo';
|
||||
import { Playground } from '@nymproject/react/playground/Playground';
|
||||
import { useIsMounted } from '@nymproject/react/hooks/useIsMounted';
|
||||
import { NymLogo } from '@nymproject/react';
|
||||
import { useIsMounted } from '@nymproject/react';
|
||||
import { NymThemeProvider } from '@nymproject/mui-theme';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { ThemeToggle } from './ThemeToggle';
|
||||
@@ -65,8 +64,6 @@ export const Content: FCWithChildren = () => {
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
<h1>Component playground</h1>
|
||||
<Playground />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import React, { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { App } from '../App';
|
||||
|
||||
describe('App', () => {
|
||||
beforeEach(() => {
|
||||
render(<App />);
|
||||
});
|
||||
it('should render without exploding', () => {
|
||||
const { container } = render(<App />);
|
||||
expect(container.firstChild).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,7 +37,7 @@
|
||||
"test:watch": "jest --watch",
|
||||
"tsc": "tsc",
|
||||
"tsc:watch": "tsc --watch",
|
||||
"lint": "eslint src",
|
||||
"lint": "echo not implemented",
|
||||
"lint:fix": "eslint src --fix"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
"docs:generate:prod": "typedoc --basePath ./docs/tsdoc/nymproject/sdk/",
|
||||
"docs:prod:build": "scripts/build-prod-docs-collect.sh",
|
||||
"docs:serve": "reload -b -d ./docs -p 3000",
|
||||
"docs:watch": "nodemon --ext ts --watch './src/**/*' --watch './typedoc.json' --exec \"yarn docs:generate\"",
|
||||
"docs:watch": "nodemon --ext ts --watch './src/**/*' --watch './typedoc.json' --exec \"pnpm docs:generate\"",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"start": "tsc -w",
|
||||
"start:dev": "nodemon --watch src -e ts,json --exec 'yarn build:dev:esm'",
|
||||
"start:dev": "nodemon --watch src -e ts,json --exec 'pnpm build:dev:esm'",
|
||||
"test": "node --experimental-fetch --experimental-vm-modules node_modules/jest/bin/jest.js -c=jest.config.mjs --no-cache",
|
||||
"tsc": "tsc --noEmit true"
|
||||
},
|
||||
@@ -42,6 +42,7 @@
|
||||
"@rollup/plugin-wasm": "^6.1.1",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/node": "^16.7.13",
|
||||
"@types/ws": "^8.5.10",
|
||||
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||
"@typescript-eslint/parser": "^5.13.0",
|
||||
"eslint": "^8.10.0",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,18 +24,19 @@
|
||||
"docs:generate:prod": "typedoc --basePath ./docs/tsdoc/nymproject/sdk/",
|
||||
"docs:prod:build": "scripts/build-prod-docs-collect.sh",
|
||||
"docs:serve": "reload -b -d ./docs -p 3000",
|
||||
"docs:watch": "nodemon --ext ts --watch './src/**/*' --watch './typedoc.json' --exec \"yarn docs:generate\"",
|
||||
"docs:watch": "nodemon --ext ts --watch './src/**/*' --watch './typedoc.json' --exec \"pnpm docs:generate\"",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"prebuild": "node scripts/showDependencyLocation.cjs",
|
||||
"start": "tsc -w",
|
||||
"start:dev": "nodemon --watch src -e ts,json --exec 'yarn build:dev:esm'",
|
||||
"start:dev": "nodemon --watch src -e ts,json --exec 'pnpm build:dev:esm'",
|
||||
"test": "node --experimental-vm-modules --no-warnings node_modules/jest/bin/jest.js -c=jest.config.mjs --no-cache",
|
||||
"tsc": "tsc --noEmit true"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nymproject/mix-fetch-wasm": ">=1.2.4-rc.2 || ^1",
|
||||
"comlink": "^4.3.1"
|
||||
"comlink": "^4.3.1",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
@@ -43,7 +44,7 @@
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@nymproject/eslint-config-react-typescript": "workspace: ^1.0.0",
|
||||
"@rollup/plugin-commonjs": "^24.0.1",
|
||||
"@rollup/plugin-inject": "^5.0.3",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
@@ -54,6 +55,7 @@
|
||||
"@rollup/plugin-wasm": "^6.1.1",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/node": "^16.7.13",
|
||||
"@types/ws": "^8.5.10",
|
||||
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||
"@typescript-eslint/parser": "^5.13.0",
|
||||
"eslint": "^8.10.0",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"@mui/styles": "^5.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@nymproject/eslint-config-react-typescript": "workspace: jnshhbwshsbsjZ hb ^1.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||
"@typescript-eslint/parser": "^5.13.0",
|
||||
"eslint": "^8.10.0",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"start": "tsc -w",
|
||||
"start:dev": "nodemon --watch src -e ts,json --exec 'yarn build:dev:esm'",
|
||||
"start:dev": "nodemon --watch src -e ts,json --exec 'pnpm build:dev:esm'",
|
||||
"test": "node --experimental-vm-modules --no-warnings node_modules/jest/bin/jest.js -c=jest.config.mjs --no-cache",
|
||||
"tsc": "tsc --noEmit true"
|
||||
},
|
||||
@@ -34,7 +34,7 @@
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@nymproject/eslint-config-react-typescript": "workspace: ^1.0.0",
|
||||
"@rollup/plugin-commonjs": "^24.0.1",
|
||||
"@rollup/plugin-inject": "^5.0.3",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
"docs:generate:prod": "typedoc --basePath ./docs/tsdoc/nymproject/sdk/",
|
||||
"docs:prod:build": "scripts/build-prod-docs-collect.sh",
|
||||
"docs:serve": "reload -b -d ./docs -p 3000",
|
||||
"docs:watch": "nodemon --ext ts --watch './src/**/*' --watch './typedoc.json' --exec \"yarn docs:generate\"",
|
||||
"docs:watch": "nodemon --ext ts --watch './src/**/*' --watch './typedoc.json' --exec \"pnpm docs:generate\"",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"start": "tsc -w",
|
||||
"start:dev": "nodemon --watch src -e ts,json --exec 'yarn build:dev:esm'",
|
||||
"start:dev": "nodemon --watch src -e ts,json --exec 'pnpm build:dev:esm'",
|
||||
"tsc": "tsc --noEmit true"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -40,6 +40,7 @@
|
||||
"@rollup/plugin-url": "^8.0.1",
|
||||
"@rollup/plugin-wasm": "^6.1.1",
|
||||
"@types/node": "^16.7.13",
|
||||
"@types/ws": "^8.5.10",
|
||||
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||
"@typescript-eslint/parser": "^5.13.0",
|
||||
"eslint": "^8.10.0",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,21 @@
|
||||
{
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.eslint.json"
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2020": true
|
||||
},
|
||||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:react-hooks/recommended"],
|
||||
"ignorePatterns": ["dist", ".eslintrc.cjs"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["react-refresh"],
|
||||
"rules": {
|
||||
"react-refresh/only-export-components": [
|
||||
"warn",
|
||||
{
|
||||
"allowConstantExport": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"react-hooks/exhaustive-deps": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -1,40 +1,25 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||
export const framework = {
|
||||
name: '@storybook/react-vite',
|
||||
options: {},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
|
||||
addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'],
|
||||
framework: '@storybook/react',
|
||||
core: {
|
||||
builder: 'webpack5',
|
||||
},
|
||||
// webpackFinal: async (config, { configType }) => {
|
||||
// // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
|
||||
// // You can change the configuration based on that.
|
||||
// // 'PRODUCTION' is used when building the static version of storybook.
|
||||
webpackFinal: async (config) => {
|
||||
config.module.rules.forEach((rule) => {
|
||||
// look for SVG import rule and replace
|
||||
// NOTE: the rule before modification is /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/
|
||||
if (rule.test?.toString().includes('svg')) {
|
||||
rule.test = /\.(ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
|
||||
}
|
||||
});
|
||||
export const docs = {
|
||||
autodocs: true,
|
||||
};
|
||||
|
||||
// handle asset loading with this
|
||||
config.module.rules.unshift({
|
||||
test: /\.svg(\?.*)?$/i,
|
||||
issuer: /\.[jt]sx?$/,
|
||||
use: ['@svgr/webpack'],
|
||||
});
|
||||
export const typescript = {
|
||||
reactDocgen: 'react-docgen-typescript',
|
||||
};
|
||||
|
||||
config.resolve.extensions = ['.tsx', '.ts', '.js'];
|
||||
config.resolve.plugins = [new TsconfigPathsPlugin()];
|
||||
const config = {
|
||||
framework: '@storybook/react-vite',
|
||||
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
|
||||
|
||||
// Return the altered config
|
||||
return config;
|
||||
},
|
||||
features: {
|
||||
emotionAlias: false,
|
||||
docs: {},
|
||||
|
||||
typescript: {
|
||||
reactDocgen: 'react-docgen-typescript',
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
@@ -1,58 +1,30 @@
|
||||
# Nym Shared React Components
|
||||
# React + TypeScript + Vite
|
||||
|
||||
This package contains shared React components that are used in other Nym projects.
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
It uses the following packages:
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [shared MUI theme](../mui-theme/README.md)
|
||||
- [webpack config](../webpack/README.md)
|
||||
- [MUI](https://https://mui.com/)
|
||||
- Typescript
|
||||
- React
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## Building
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
```
|
||||
yarn
|
||||
yarn build
|
||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||
|
||||
- Configure the top-level `parserOptions` property like this:
|
||||
|
||||
```js
|
||||
export default {
|
||||
// other rules...
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
project: ['./tsconfig.json', './tsconfig.node.json'],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
Run watch mode with:
|
||||
|
||||
```
|
||||
yarn watch
|
||||
```
|
||||
|
||||
Or you can run Storybook with:
|
||||
|
||||
```
|
||||
yarn storybook
|
||||
```
|
||||
|
||||
Or you can run the [example project](../react-webpack-with-theme-example/README.md) in dev mode and this package in watch mode, and test results in the example project's dev server output.
|
||||
|
||||
## Playground
|
||||
|
||||
There are [playground components](./src/playground/index.tsx) that are intended to be used during development to see the effects are changes to the MUI theme or shared components at a glance.
|
||||
|
||||
They are available in Storybook from [src/stories/Playground.stories.tsx](./src/stories/Playground.stories.tsx).
|
||||
|
||||
> ℹ️ **Tip**: use the playground to make sure components stay consistent and you don't break other components while making changes
|
||||
|
||||
## Shared assets
|
||||
|
||||
This project uses [shared asset files](../../assets/README.md) such as favicons and logos.
|
||||
|
||||
> ℹ️ **Tip**: use to keep your project consistent with Nym's branding and so that it automatically receives changes when the shared assets change. Please try to avoid duplicating the files in the shared assets directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
This package is not published to NPM ... yet.
|
||||
|
||||
## TODO
|
||||
|
||||
- ugprade to React 18
|
||||
- upgrade Storybook
|
||||
- upgrade MUI
|
||||
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
|
||||
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
|
||||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Nym React Components</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
+6
-5
@@ -1,12 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import { ChangeEvent } from 'react';
|
||||
import { InputAdornment, TextField } from '@mui/material';
|
||||
import { InputAdornment, TextField, SxProps } from '@mui/material';
|
||||
import { TextFieldProps } from '@mui/material/TextField/TextField';
|
||||
import { validateWalletAddress } from '@nymproject/types';
|
||||
import DoneIcon from '@mui/icons-material/Done';
|
||||
import { SxProps } from '@mui/system';
|
||||
|
||||
export const WalletAddressFormField: FCWithChildren<{
|
||||
export type WalletAddressFormFieldProps = {
|
||||
showTickOnValid?: boolean;
|
||||
fullWidth?: boolean;
|
||||
required?: boolean;
|
||||
@@ -20,7 +19,9 @@ export const WalletAddressFormField: FCWithChildren<{
|
||||
textFieldProps?: TextFieldProps;
|
||||
errorText?: string;
|
||||
sx?: SxProps;
|
||||
}> = ({
|
||||
};
|
||||
|
||||
export const WalletAddressFormField = ({
|
||||
required,
|
||||
fullWidth,
|
||||
placeholder,
|
||||
@@ -33,7 +34,7 @@ export const WalletAddressFormField: FCWithChildren<{
|
||||
onValidate,
|
||||
textFieldProps,
|
||||
showTickOnValid = true,
|
||||
}) => {
|
||||
}: WalletAddressFormFieldProps) => {
|
||||
const [value, setValue] = React.useState<string | undefined>(initialValue);
|
||||
const [validationError, setValidationError] = React.useState<string | undefined>();
|
||||
|
||||
+3
-4
@@ -1,14 +1,13 @@
|
||||
import * as React from 'react';
|
||||
import { Box, Collapse, Alert, IconButton, Typography, Divider } from '@mui/material';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { SxProps } from '@mui/system';
|
||||
import { SxProps } from '@mui/material';
|
||||
|
||||
export interface BannerProps {
|
||||
export type BannerProps = {
|
||||
open: boolean;
|
||||
onClick: () => void;
|
||||
height?: number;
|
||||
sx?: SxProps;
|
||||
}
|
||||
};
|
||||
|
||||
export const MaintenanceBanner = (props: BannerProps) => {
|
||||
const { open, onClick, height, sx } = props;
|
||||
+5
-8
@@ -1,22 +1,21 @@
|
||||
import React from 'react';
|
||||
import { Box, Typography, Tooltip } from '@mui/material';
|
||||
import { CopyToClipboard } from '../clipboard/CopyToClipboard';
|
||||
|
||||
const AddressTooltip: FCWithChildren<{ visible?: boolean; address?: string }> = ({ visible, address, children }) => {
|
||||
type AddressTooltipProps = { visible?: boolean; address?: string; children: React.ReactNode };
|
||||
|
||||
const AddressTooltip = ({ visible, address, children }: AddressTooltipProps) => {
|
||||
if (!visible || !address) {
|
||||
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip title={address} arrow>
|
||||
{/* eslint-disable-next-line react/jsx-no-useless-fragment */}
|
||||
<>{children}</>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
type ClientAddressProps = {
|
||||
export type ClientAddressProps = {
|
||||
address: string;
|
||||
withLabel?: boolean;
|
||||
withCopy?: boolean;
|
||||
@@ -24,7 +23,7 @@ type ClientAddressProps = {
|
||||
showEntireAddress?: boolean;
|
||||
};
|
||||
|
||||
export const ClientAddressDisplay = ({
|
||||
export const ClientAddress = ({
|
||||
withLabel,
|
||||
withCopy,
|
||||
smallIcons,
|
||||
@@ -48,5 +47,3 @@ export const ClientAddressDisplay = ({
|
||||
{withCopy && <CopyToClipboard smallIcons={smallIcons} value={address} />}
|
||||
</Box>
|
||||
);
|
||||
|
||||
export const ClientAddress = ({ ...props }: ClientAddressProps) => <ClientAddressDisplay {...props} />;
|
||||
+4
-2
@@ -4,13 +4,15 @@ import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||
import DoneIcon from '@mui/icons-material/Done';
|
||||
import { useClipboard } from 'use-clipboard-copy';
|
||||
|
||||
export const CopyToClipboard: FCWithChildren<{
|
||||
export type CopyToClipboardProps = {
|
||||
value: string;
|
||||
tooltip?: React.ReactNode;
|
||||
onCopy?: (value: string) => void;
|
||||
smallIcons?: boolean;
|
||||
sx?: SxProps;
|
||||
}> = ({ value, tooltip, onCopy, smallIcons, sx }) => {
|
||||
};
|
||||
|
||||
export const CopyToClipboard = ({ value, tooltip, onCopy, smallIcons, sx }: CopyToClipboardProps) => {
|
||||
const copy = useClipboard();
|
||||
const [showConfirmation, setShowConfirmation] = React.useState<boolean>(false);
|
||||
const handleCopy = (e: React.MouseEvent<SVGSVGElement>) => {
|
||||
+6
-5
@@ -1,13 +1,14 @@
|
||||
import * as React from 'react';
|
||||
import { PaletteMode, useTheme } from '@mui/material';
|
||||
import TokenLight from '@assets/token/token-light.svg';
|
||||
import TokenDark from '@assets/token/token-dark.svg';
|
||||
import TokenLight from '@assets/token/token-light.svg?react';
|
||||
import TokenDark from '@assets/token/token-dark.svg?react';
|
||||
|
||||
export const CoinMark: FCWithChildren<{
|
||||
export type CoinMarkProps = {
|
||||
mode?: PaletteMode;
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
}> = ({ mode, ...props }) => {
|
||||
};
|
||||
|
||||
export const CoinMark = ({ mode, ...props }: CoinMarkProps) => {
|
||||
const theme = useTheme();
|
||||
const modeWithTheme = mode || theme.palette.mode;
|
||||
if (modeWithTheme === 'light') {
|
||||
@@ -0,0 +1,13 @@
|
||||
import { useTheme } from '@mui/material';
|
||||
import TokenLight from '@assets/token/token-light-testnet.svg?react';
|
||||
import TokenDark from '@assets/token/token-dark-testnet.svg?react';
|
||||
import { CoinMarkProps } from './CoinMark';
|
||||
|
||||
export const CoinMarkTestnet = ({ mode, ...props }: CoinMarkProps) => {
|
||||
const theme = useTheme();
|
||||
const modeWithTheme = mode || theme.palette.mode;
|
||||
if (modeWithTheme === 'light') {
|
||||
return <TokenLight {...props} />;
|
||||
}
|
||||
return <TokenDark {...props} />;
|
||||
};
|
||||
+10
-3
@@ -1,16 +1,23 @@
|
||||
import * as React from 'react';
|
||||
import type { DecCoin } from '@nymproject/types';
|
||||
import { Stack, SxProps } from '@mui/material';
|
||||
import { CurrencyWithCoinMark } from './CurrencyWithCoinMark';
|
||||
import { CURRENCY_AMOUNT_SPACING, CurrencyAmount } from './CurrencyAmount';
|
||||
|
||||
export const Currency: FCWithChildren<{
|
||||
export type CurrencyProps = {
|
||||
majorAmount?: DecCoin;
|
||||
showDenom?: boolean;
|
||||
showCoinMark?: boolean;
|
||||
coinMarkPrefix?: boolean;
|
||||
sx?: SxProps;
|
||||
}> = ({ majorAmount, sx, showDenom = true, showCoinMark = false, coinMarkPrefix = false }) => {
|
||||
};
|
||||
|
||||
export const Currency = ({
|
||||
majorAmount,
|
||||
sx,
|
||||
showDenom = true,
|
||||
showCoinMark = false,
|
||||
coinMarkPrefix = false,
|
||||
}: CurrencyProps) => {
|
||||
if (!majorAmount || !majorAmount.amount) {
|
||||
return (
|
||||
<Stack direction="row" sx={sx}>
|
||||
+14
-10
@@ -1,13 +1,11 @@
|
||||
/* eslint-disable react/no-array-index-key */
|
||||
import * as React from 'react';
|
||||
import type { DecCoin } from '@nymproject/types';
|
||||
import { Stack, SxProps, Typography } from '@mui/material';
|
||||
|
||||
export const CURRENCY_AMOUNT_SPACING = 0.35;
|
||||
|
||||
const toReverseChunks = (value: String, size: number = 3): Array<string> => {
|
||||
const toReverseChunks = (value: string, size: number = 3): Array<string> => {
|
||||
const reversed = value.split('').reverse();
|
||||
const chunks: Array<Array<String>> = [];
|
||||
const chunks: Array<Array<string>> = [];
|
||||
let chunksIndex = 0;
|
||||
reversed.forEach((char, index) => {
|
||||
if (index > 0 && index % size === 0) {
|
||||
@@ -21,8 +19,8 @@ const toReverseChunks = (value: String, size: number = 3): Array<string> => {
|
||||
return chunks.map((chars) => chars.reverse().join('')).reverse();
|
||||
};
|
||||
|
||||
const toChunks = (value: String, size: number = 3): Array<string> => {
|
||||
const chunks: Array<Array<String>> = [];
|
||||
const toChunks = (value: string, size: number = 3): Array<string> => {
|
||||
const chunks: Array<Array<string>> = [];
|
||||
let chunksIndex = 0;
|
||||
value.split('').forEach((char, index) => {
|
||||
if (index > 0 && index % size === 0) {
|
||||
@@ -36,11 +34,13 @@ const toChunks = (value: String, size: number = 3): Array<string> => {
|
||||
return chunks.map((chars) => chars.join(''));
|
||||
};
|
||||
|
||||
export const CurrencyAmountString: FCWithChildren<{
|
||||
export type CurrencyAmountStringProps = {
|
||||
majorAmount?: string;
|
||||
showSeparators?: boolean;
|
||||
sx?: SxProps;
|
||||
}> = ({ majorAmount, sx, showSeparators = true }) => {
|
||||
};
|
||||
|
||||
export const CurrencyAmountString = ({ majorAmount, sx, showSeparators = true }: CurrencyAmountStringProps) => {
|
||||
if (!majorAmount) {
|
||||
return (
|
||||
<Stack direction="row" sx={sx}>
|
||||
@@ -93,8 +93,12 @@ export const CurrencyAmountString: FCWithChildren<{
|
||||
);
|
||||
};
|
||||
|
||||
export const CurrencyAmount: FCWithChildren<{
|
||||
export type CurrencyAmountProps = {
|
||||
majorAmount?: DecCoin;
|
||||
showSeparators?: boolean;
|
||||
sx?: SxProps;
|
||||
}> = ({ majorAmount, ...props }) => <CurrencyAmountString majorAmount={majorAmount?.amount} {...props} />;
|
||||
};
|
||||
|
||||
export const CurrencyAmount = ({ majorAmount, ...props }: CurrencyAmountProps) => (
|
||||
<CurrencyAmountString majorAmount={majorAmount?.amount} {...props} />
|
||||
);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user