Compare commits
103
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52481ccaf5 | ||
|
|
483345942d | ||
|
|
d71871566b | ||
|
|
10afa3c1d4 | ||
|
|
ecd362615e | ||
|
|
0d9bd67465 | ||
|
|
b5aa92f007 | ||
|
|
2955790be1 | ||
|
|
89ff9309e9 | ||
|
|
e1df3489f6 | ||
|
|
f0fa9ca5e1 | ||
|
|
9d92477c2a | ||
|
|
b1a198be85 | ||
|
|
5fb385d43c | ||
|
|
8014b279fe | ||
|
|
f4bde57294 | ||
|
|
2e5ff07824 | ||
|
|
7accb42793 | ||
|
|
9229e7f686 | ||
|
|
b570b9c4c1 | ||
|
|
ed78261aad | ||
|
|
363ca9c6e1 | ||
|
|
bafd3c384c | ||
|
|
3b830abe07 | ||
|
|
1787e22b69 | ||
|
|
f105133959 | ||
|
|
aff0e46d23 | ||
|
|
7e4aafcb77 | ||
|
|
643d5408cd | ||
|
|
2a2af3ba9c | ||
|
|
8d4e4a1228 | ||
|
|
84068c8081 | ||
|
|
e1185b9a96 | ||
|
|
f390448c24 | ||
|
|
70943c523c | ||
|
|
dcb79e70d3 | ||
|
|
cc72cdbe16 | ||
|
|
3fd1817e1e | ||
|
|
b483c13f81 | ||
|
|
bde7a9fbf9 | ||
|
|
5fd93ee9c8 | ||
|
|
9ac07fd98a | ||
|
|
9c975ed822 | ||
|
|
138bf7da00 | ||
|
|
3e7fe517f3 | ||
|
|
4f960d09b3 | ||
|
|
351a5aaf96 | ||
|
|
381d9011a0 | ||
|
|
861760b4f9 | ||
|
|
18f1c0014c | ||
|
|
474543d91b | ||
|
|
662753c74b | ||
|
|
71aa8882bc | ||
|
|
ecfbccf8ed | ||
|
|
2aad6b1a14 | ||
|
|
8463d371ad | ||
|
|
0914e7ce4b | ||
|
|
7c82144f37 | ||
|
|
17ad0cc975 | ||
|
|
eb58dcd350 | ||
|
|
c8c0bf2cc0 | ||
|
|
00579fcb1f | ||
|
|
5e13173efb | ||
|
|
3a6c0554cc | ||
|
|
d4b237a6ba | ||
|
|
5e765f3172 | ||
|
|
5ef8c11e6e | ||
|
|
84bae12def | ||
|
|
c5b22f5bfb | ||
|
|
071dcc61a8 | ||
|
|
ce0ccdfebc | ||
|
|
f1524d3fcd | ||
|
|
82e5128ba1 | ||
|
|
2bfc3abd15 | ||
|
|
bd3b557f3d | ||
|
|
c899da52c2 | ||
|
|
b9c4057ce5 | ||
|
|
d02feee5c6 | ||
|
|
6d1ab36a72 | ||
|
|
5690fe91a8 | ||
|
|
1daae6a233 | ||
|
|
cd35a34246 | ||
|
|
77ada964b5 | ||
|
|
d7404bcd76 | ||
|
|
91862701a7 | ||
|
|
0136efd78f | ||
|
|
c3a4954d0d | ||
|
|
528fd96721 | ||
|
|
155923ff8e | ||
|
|
5f7e60d22f | ||
|
|
351583ce8f | ||
|
|
88bf58b974 | ||
|
|
fcda4d7fcd | ||
|
|
b1b0039b33 | ||
|
|
6854980b32 | ||
|
|
d8aac83f2d | ||
|
|
5c17045752 | ||
|
|
8863209342 | ||
|
|
462bf6b8b5 | ||
|
|
e0b701e05a | ||
|
|
eca212eee0 | ||
|
|
c25858037a | ||
|
|
081f5b48e2 |
@@ -1,15 +1,14 @@
|
||||
---
|
||||
name: Release
|
||||
about:
|
||||
A template to outline the steps needed to for a successful release of our frontend apps
|
||||
about: A template to outline the steps needed to for a successful release of our frontend apps
|
||||
title: 'Release [add dapp version]-core-[add core version]'
|
||||
labels:
|
||||
labels:
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
### Tasks
|
||||
|
||||
- [ ] Review [link to core release](xxx)
|
||||
- [ ] Review [link to core release](xxx)
|
||||
- [ ] Tag frontend-monorepo
|
||||
- [ ] Create release and generate release notes
|
||||
- [ ] Run `@smoke` tests
|
||||
|
||||
@@ -13,7 +13,7 @@ env:
|
||||
|
||||
jobs:
|
||||
add_issue:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: 'Add issue to project board'
|
||||
run: |
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
name: CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- release/*
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
jobs:
|
||||
lint-test-build:
|
||||
runs-on: ubuntu-22.04
|
||||
name: '(CI) lint + unit test + build'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||
cache: yarn
|
||||
|
||||
- name: Install root dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||
uses: nrwl/nx-set-shas@v3
|
||||
with:
|
||||
main-branch-name: develop
|
||||
|
||||
- name: Check formatting
|
||||
run: yarn nx format:check
|
||||
|
||||
- name: Lint affected
|
||||
run: yarn nx affected:lint --max-warnings=0
|
||||
|
||||
- name: Build affected spec
|
||||
run: yarn nx affected --target=build-spec
|
||||
|
||||
- name: Test affected
|
||||
run: yarn nx affected:test
|
||||
|
||||
- name: Build affected
|
||||
run: yarn nx affected:build
|
||||
|
||||
# See affected apps
|
||||
- name: See affected apps
|
||||
run: |
|
||||
echo ">>>> debug"
|
||||
echo "NX Version: $nx_version"
|
||||
echo "NX_BASE: ${{ env.NX_BASE }}"
|
||||
echo "NX_HEAD: ${{ env.NX_HEAD }}"
|
||||
echo ">>>> eof debug"
|
||||
|
||||
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)"
|
||||
echo -n "Affected projects: $affected"
|
||||
|
||||
projects_e2e=""
|
||||
if [[ $affected == *"governance"* ]]; then projects_e2e+='"governance-e2e" '; fi
|
||||
if [[ $affected == *"trading"* ]]; then projects_e2e+='"trading-e2e" '; fi
|
||||
if [[ $affected == *"explorer"* ]]; then projects_e2e+='"explorer-e2e" '; fi
|
||||
if [[ -z "$projects_e2e" ]]; then projects_e2e+='"governance-e2e" "trading-e2e" "explorer-e2e" '; fi
|
||||
projects_e2e=${projects_e2e%?}
|
||||
projects_e2e=[${projects_e2e// /,}]
|
||||
echo PROJECTS_E2E=$projects_e2e >> $GITHUB_ENV
|
||||
echo PROJECTS=$(echo $projects_e2e | sed 's|-e2e||g') >> $GITHUB_ENV
|
||||
|
||||
outputs:
|
||||
projects: ${{ env.PROJECTS }}
|
||||
projects-e2e: ${{ env.PROJECTS_E2E }}
|
||||
|
||||
cypress:
|
||||
needs: lint-test-build
|
||||
name: '(CI) cypress'
|
||||
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
|
||||
uses: ./.github/workflows/cypress-run.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
|
||||
tags: '@smoke @regression'
|
||||
|
||||
publish-dist:
|
||||
needs: lint-test-build
|
||||
name: '(CD) publish dist'
|
||||
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
|
||||
uses: ./.github/workflows/publish-dist.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
projects: ${{ needs.lint-test-build.outputs.projects }}
|
||||
|
||||
# Report single result at the end, to avoid mess with required checks in PR
|
||||
cypress-result:
|
||||
if: ${{ always() }}
|
||||
needs: cypress
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- run: |
|
||||
result="${{ needs.cypress.result }}"
|
||||
if [[ $result == "success" || $result == "skipped" ]]; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
@@ -13,7 +13,7 @@ on:
|
||||
jobs:
|
||||
cypress-run:
|
||||
name: Run Cypress Trading tests -- live environment
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Cypress Run
|
||||
name: (CI) Cypress Run
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
|
||||
@@ -8,22 +8,25 @@ on:
|
||||
jobs:
|
||||
master:
|
||||
name: Generate Queries
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Use Node.js 16
|
||||
id: Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16.15.1
|
||||
node-version-file: '.nvmrc'
|
||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||
cache: yarn
|
||||
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Generate queries
|
||||
run: node ./scripts/get-queries.js
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: queries
|
||||
|
||||
@@ -3,21 +3,28 @@ name: Verify PR title
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, ready_for_review, reopened, edited, synchronize]
|
||||
types:
|
||||
- opened
|
||||
- ready_for_review
|
||||
- reopened
|
||||
- edited
|
||||
- synchronize
|
||||
jobs:
|
||||
lint_pr:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Use Node.js 16
|
||||
id: Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16.15.1
|
||||
node-version-file: '.nvmrc'
|
||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||
cache: yarn
|
||||
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Check PR title
|
||||
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
name: PR Validations
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- main
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
jobs:
|
||||
pr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout frontend mono repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check node version
|
||||
id: node-version
|
||||
run: |
|
||||
npmVersion=$(cat .nvmrc | head -n 1)
|
||||
echo ::set-output name=npmVersion::${npmVersion}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ steps.node-version.outputs.npmVersion }}
|
||||
|
||||
# Check SHAs
|
||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||
uses: nrwl/nx-set-shas@v2
|
||||
with:
|
||||
main-branch-name: ${{ github.base_ref || github.ref_name }}
|
||||
set-environment-variables-for-job: true
|
||||
|
||||
# See affected apps
|
||||
- name: See affected apps
|
||||
run: |
|
||||
nx_version=$(cat package.json | grep '"nx"' | cut -d ':' -f 2 | tr -d '",[:space:]')
|
||||
rm package.json yarn.lock
|
||||
yarn add nx@$nx_version
|
||||
affected=$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)
|
||||
echo -n "Affected projects: $affected"
|
||||
projects_e2e=""
|
||||
if [[ $affected == *"governance"* ]]; then projects_e2e+='"governance-e2e" '; fi
|
||||
if [[ $affected == *"trading"* ]]; then projects_e2e+='"trading-e2e" '; fi
|
||||
if [[ $affected == *"explorer"* ]]; then projects_e2e+='"explorer-e2e" '; fi
|
||||
if [[ -z "$projects_e2e" ]]; then projects_e2e+='"governance-e2e" "trading-e2e" "explorer-e2e" '; fi
|
||||
projects_e2e=${projects_e2e%?}
|
||||
projects_e2e=[${projects_e2e// /,}]
|
||||
echo PROJECTS_E2E=$projects_e2e >> $GITHUB_ENV
|
||||
echo PROJECTS=$(echo $projects_e2e | sed 's|-e2e||g') >> $GITHUB_ENV
|
||||
|
||||
outputs:
|
||||
projects: ${{ env.PROJECTS }}
|
||||
projects-e2e: ${{ env.PROJECTS_E2E }}
|
||||
|
||||
run-cypress:
|
||||
needs: pr
|
||||
if: ${{ needs.pr.outputs.projects != '[]' }}
|
||||
uses: ./.github/workflows/cypress-run.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
projects: ${{ needs.pr.outputs.projects-e2e }}
|
||||
tags: '@smoke @regression'
|
||||
|
||||
run-docker-build:
|
||||
needs: pr
|
||||
if: ${{ needs.pr.outputs.projects != '[]' }}
|
||||
uses: ./.github/workflows/publish-docker-containers.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
projects: ${{ needs.pr.outputs.projects }}
|
||||
|
||||
# Report single result at the end, to avoid mess with required checks in PR
|
||||
result:
|
||||
if: ${{ always() }}
|
||||
needs: run-cypress
|
||||
runs-on: ubuntu-latest
|
||||
name: Cypress result
|
||||
steps:
|
||||
- run: |
|
||||
result="${{ needs.run-cypress.result }}"
|
||||
if [[ $result == "success" || $result == "skipped" ]]; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
jobs:
|
||||
master:
|
||||
name: Generate Queries
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
+56
-42
@@ -1,4 +1,4 @@
|
||||
name: Docker build
|
||||
name: (CD) Publish docker + s3
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
@@ -8,13 +8,13 @@ on:
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
master:
|
||||
publish-dist:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
app: ${{ fromJSON(inputs.projects) }}
|
||||
name: ${{ matrix.app }}
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
@@ -29,41 +29,6 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
# https://docs.github.com/en/actions/learn-github-actions/contexts
|
||||
# https://github.com/actions/checkout#Checkout-pull-request-HEAD-commit-instead-of-merge-commit
|
||||
- name: Determine Docker Image tag
|
||||
id: tags
|
||||
run: |
|
||||
npmVersion=$(cat .nvmrc | head -n 1)
|
||||
versionTag=${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || github.event.pull_request.head.sha }}
|
||||
echo ::set-output name=npmVersion::${npmVersion}
|
||||
echo ::set-output name=version::${versionTag}
|
||||
|
||||
- name: Print config
|
||||
run: |
|
||||
git rev-parse --verify HEAD
|
||||
git status
|
||||
echo "steps.tags.outputs.version=${{ steps.tags.outputs.version }}"
|
||||
|
||||
- name: Build and export to local Docker
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
load: true
|
||||
build-args: |
|
||||
APP=${{ matrix.app }}
|
||||
NODE_VERSION=${{ steps.tags.outputs.npmVersion }}
|
||||
tags: |
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||
|
||||
- name: Sanity check docker image
|
||||
run: |
|
||||
echo "Check .env file"
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat .env
|
||||
echo "Check ipfs-hash"
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat ipfs-hash
|
||||
echo "List html directory"
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local ls -lah
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
@@ -71,17 +36,66 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
# https://docs.github.com/en/actions/learn-github-actions/contexts
|
||||
- name: Check node version
|
||||
id: tags
|
||||
run: |
|
||||
nodeVersion=$(cat .nvmrc | head -n 1)
|
||||
echo ::set-output name=nodeVersion::${nodeVersion}
|
||||
|
||||
if [[ "${{ github.event_name }}" = "push" ]]; then
|
||||
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
|
||||
bucketName="${{ github.event.repository.name }}-$envName"
|
||||
echo ::set-output name=bucketName::${bucketName}
|
||||
echo ::set-output name=envName::${envName}
|
||||
fi
|
||||
|
||||
- name: Build and export to local Docker
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
load: true
|
||||
build-args: |
|
||||
APP=${{ matrix.app }}
|
||||
NODE_VERSION=${{ steps.tags.outputs.nodeVersion }}
|
||||
ENV_NAME=${{ steps.tags.outputs.envName || '' }}
|
||||
tags: |
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||
|
||||
- name: Sanity check docker image
|
||||
run: |
|
||||
echo "Check ipfs-hash"
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat ipfs-hash
|
||||
|
||||
echo "List html directory"
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local ls -lah
|
||||
|
||||
echo "Copy dist to local filesystem"
|
||||
docker create --name=dist ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||
docker cp dist:/usr/share/nginx/html dist
|
||||
|
||||
echo "Check local dist"
|
||||
ls -al dist
|
||||
|
||||
- name: Publish dist as docker image
|
||||
uses: docker/build-push-action@v3
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
with:
|
||||
push: true
|
||||
build-args: |
|
||||
APP=${{ matrix.app }}
|
||||
NODE_VERSION=${{ steps.tags.outputs.npmVersion }}
|
||||
NODE_VERSION=${{ steps.tags.outputs.nodeVersion }}
|
||||
tags: |
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:latest
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ steps.tags.outputs.version }}
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
# - uses: shallwefootball/s3-upload-action@master
|
||||
# if: ${{ github.event_name == 'push' }}
|
||||
# name: Upload dist S3
|
||||
# with:
|
||||
# aws_key_id: ${{ secrets.AWS_KEY_ID }}
|
||||
# aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY}}
|
||||
# aws_bucket: ${{ steps.tags.outputs.bucketName }}
|
||||
# source_dir: 'dist'
|
||||
|
||||
- name: Add preview label
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
@@ -8,6 +8,7 @@ on:
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- announcements
|
||||
- ui-toolkit
|
||||
- react-helpers
|
||||
- tailwindcss-config
|
||||
@@ -18,29 +19,27 @@ on:
|
||||
jobs:
|
||||
publish:
|
||||
name: Build & Publish - Tag
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: 'read'
|
||||
actions: 'read'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: User Node.js 16
|
||||
id: Node
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.15.1
|
||||
- name: Restore node_modules from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: node_modules-${{ hashFiles('**/yarn.lock') }}
|
||||
node-version-file: '.nvmrc'
|
||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||
cache: yarn
|
||||
|
||||
- name: Install root dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Build project
|
||||
run: yarn nx build ${{inputs.project}}
|
||||
|
||||
- name: Publish project to @vegaprotocol
|
||||
uses: JS-DevTools/npm-publish@v1
|
||||
with:
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
name: Unit tests & build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- main
|
||||
pull_request:
|
||||
jobs:
|
||||
pr:
|
||||
name: Test and lint - PR
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: 'read'
|
||||
actions: 'read'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||
uses: nrwl/nx-set-shas@v2
|
||||
with:
|
||||
main-branch-name: ${{ github.base_ref }}
|
||||
- name: Use Node.js 16
|
||||
id: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.15.1
|
||||
- name: Restore node_modules from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: node_modules-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Install root dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Check formatting
|
||||
run: yarn nx format:check
|
||||
- name: Lint affected
|
||||
run: yarn nx affected:lint --max-warnings=0
|
||||
- name: Test affected
|
||||
run: yarn nx affected:test
|
||||
- name: Build affected
|
||||
run: yarn nx affected:build
|
||||
- name: Build affected spec
|
||||
run: yarn nx affected --target=build-spec
|
||||
+2
-7
@@ -4,6 +4,7 @@ FROM --platform=amd64 node:${NODE_VERSION}-alpine3.16 as build
|
||||
WORKDIR /app
|
||||
# Argument to allow building of different apps
|
||||
ARG APP
|
||||
ARG ENV_NAME=""
|
||||
RUN apk add --update --no-cache \
|
||||
python3 \
|
||||
make \
|
||||
@@ -18,16 +19,10 @@ RUN sh ./docker-build.sh
|
||||
# if this fails you need to docker pull nginx:1.23-alpine and pin new SHA
|
||||
# this is to ensure that we run always same version of alpine to make sure ipfs is indempotent
|
||||
FROM --platform=amd64 nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
|
||||
ARG APP
|
||||
# configuration of system
|
||||
RUN apk add --no-cache bash go-ipfs
|
||||
EXPOSE 80
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
CMD ["/entrypoint.sh"]
|
||||
|
||||
# Copy dist
|
||||
WORKDIR /usr/share/nginx/html
|
||||
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=build /app/dist/apps/${APP} /usr/share/nginx/html
|
||||
COPY ./apps/${APP}/.env .env
|
||||
RUN ipfs init && echo "$(ipfs add -rQ .)" > ipfs-hash
|
||||
RUN apk add --no-cache go-ipfs; ipfs init && echo "$(ipfs add -rQ .)" > ipfs-hash; apk del go-ipfs
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n00.stagnet3.vega.xyz/websocket
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
|
||||
NX_VEGA_NETWORKS='{"SANDBOX":"https://sandbox.explorer.vega.xyz","STAGNET1":"https://stagnet1.token.vega.xyz", "STAGNET3":"https://stagnet3.explorer.vega.xyz","VALIDATOR_TESTNET":"https://validator-testnet.fairground.wtf","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||
NX_VEGA_NETWORKS='{"STAGNET1":"https://stagnet1.token.vega.xyz", "STAGNET3":"https://stagnet3.explorer.vega.xyz","VALIDATOR_TESTNET":"https://validator-testnet.fairground.wtf","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||
NX_VEGA_ENV=STAGNET3
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
|
||||
@@ -3,6 +3,7 @@ NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
NX_VEGA_ENV=CUSTOM
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -8,3 +8,4 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://dev.token.vega.xyz
|
||||
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
@@ -6,3 +6,4 @@ NX_VEGA_ENV=MAINNET
|
||||
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest/
|
||||
NX_ETHERSCAN_URL=https://etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://token.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
@@ -1,19 +0,0 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://tm.be.mainnet-mirror.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.xyz/websocket
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
|
||||
NX_VEGA_ENV=MIRROR
|
||||
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.xyz/rest/
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://mainnet-mirror.token.vega.xyz
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
NX_EXPLORER_GENESIS=1
|
||||
NX_EXPLORER_GOVERNANCE=1
|
||||
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
NX_EXPLORER_VALIDATORS=1
|
||||
NX_EXPLORER_MARKETS=0
|
||||
NX_EXPLORER_ORACLES=0
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
@@ -1,11 +0,0 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_ENV=SANDBOX
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/sandbox/vegawallet-sandbox.toml
|
||||
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_TENDERMINT_URL=https://tm.sandbox.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.sandbox.vega.xyz/websocket
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://sandbox.token.vega.xyz
|
||||
@@ -11,3 +11,4 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://stagnet1.token.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
@@ -5,3 +5,4 @@ NX_VEGA_ENV=STAGNET3
|
||||
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
|
||||
NX_VEGA_GOVERNANCE_URL=https://stagnet3.token.vega.xyz
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases/
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
@@ -8,3 +8,4 @@ NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://token.fairground.wtf
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
@@ -5,8 +5,9 @@ NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
||||
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
|
||||
NX_VEGA_GOVERNANCE_URL=https://validator-testnet.governance.vega.xyz
|
||||
NX_TENDERMINT_URL=https://tm-be.validators-testnet.vega.rocks
|
||||
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/
|
||||
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||
|
||||
@@ -4,3 +4,4 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket
|
||||
NX_VEGA_ENV=CUSTOM
|
||||
NX_BLOCK_EXPLORER=
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
||||
|
||||
@@ -3,16 +3,14 @@ import {
|
||||
useAssetDetailsDialogStore,
|
||||
} from '@vegaprotocol/assets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { AnnouncementBanner } from '@vegaprotocol/announcements';
|
||||
import {
|
||||
AnnouncementBanner,
|
||||
BackgroundVideo,
|
||||
BreadcrumbsContainer,
|
||||
ButtonLink,
|
||||
ExternalLink,
|
||||
Icon,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import classNames from 'classnames';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
isRouteErrorResponse,
|
||||
Link,
|
||||
@@ -37,35 +35,9 @@ const DialogsContainer = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const MainnetSimAd = () => {
|
||||
const [shouldDisplayBanner, setShouldDisplayBanner] = useState<boolean>(true);
|
||||
|
||||
// Return an empty div so that the grid layout in _app.page.ts
|
||||
// renders correctly
|
||||
if (!shouldDisplayBanner) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return (
|
||||
<AnnouncementBanner>
|
||||
<div className="grid grid-cols-[auto_1fr] gap-4 font-alpha calt uppercase text-center text-lg text-white">
|
||||
<button
|
||||
className="flex items-center"
|
||||
onClick={() => setShouldDisplayBanner(false)}
|
||||
>
|
||||
<Icon name="cross" className="w-6 h-6" ariaLabel="dismiss" />
|
||||
</button>
|
||||
<div>
|
||||
<span className="pr-4">Mainnet sim 3 is live!</span>
|
||||
<ExternalLink href="https://fairground.wtf/">Learn more</ExternalLink>
|
||||
</div>
|
||||
</div>
|
||||
</AnnouncementBanner>
|
||||
);
|
||||
};
|
||||
|
||||
export const Layout = () => {
|
||||
const isHome = Boolean(useMatch(Routes.HOME));
|
||||
const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@@ -79,7 +51,12 @@ export const Layout = () => {
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<MainnetSimAd />
|
||||
{ANNOUNCEMENTS_CONFIG_URL && (
|
||||
<AnnouncementBanner
|
||||
app="explorer"
|
||||
configUrl={ANNOUNCEMENTS_CONFIG_URL}
|
||||
/>
|
||||
)}
|
||||
<Header />
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -13,6 +13,8 @@ NX_LOCAL_PROVIDER_URL=http://localhost:8545/
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND=false
|
||||
|
||||
@@ -56,7 +56,7 @@ describe(
|
||||
navigateTo(navigation.proposals);
|
||||
});
|
||||
|
||||
// 3001-VOTE-055
|
||||
// 3001-VOTE-050 3001-VOTE-054 3001-VOTE-055 3002-PROP-019
|
||||
it('Newly created raw proposal details - shows proposal title and full description', function () {
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
|
||||
@@ -128,7 +128,7 @@ context(
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
// 3001-VOTE-048 3001-VOTE-049
|
||||
// 3001-VOTE-048 3001-VOTE-049 3001-VOTE-050
|
||||
it('Able to fail proposal due to lack of participation', function () {
|
||||
const proposalTitle = 'Add New free form proposal with short enactment';
|
||||
const proposalTx = createFreeFormProposalTxBody();
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
waitForSpinner,
|
||||
navigateTo,
|
||||
navigation,
|
||||
closeDialog,
|
||||
} from '../../support/common.functions';
|
||||
import {
|
||||
clickOnValidatorFromList,
|
||||
@@ -41,7 +42,6 @@ const vegaWalletNameElement = '[data-testid="wallet-name"]';
|
||||
const vegaWallet = '[data-testid="vega-wallet"]';
|
||||
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
|
||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||
const dialogCloseButton = '[data-testid="dialog-close"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const rawProposalData = '[data-testid="proposal-data"]';
|
||||
const minVoteButton = '[data-testid="min-vote"]';
|
||||
@@ -177,7 +177,7 @@ context(
|
||||
'be.visible'
|
||||
);
|
||||
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
||||
cy.get(dialogCloseButton).click();
|
||||
closeDialog();
|
||||
waitForProposalSync();
|
||||
navigateTo(navigation.proposals);
|
||||
cy.get(rejectProposalsLink).click();
|
||||
@@ -214,7 +214,7 @@ context(
|
||||
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
cy.get(dialogCloseButton).click();
|
||||
closeDialog();
|
||||
});
|
||||
|
||||
// 3002-PROP-009
|
||||
@@ -227,7 +227,7 @@ context(
|
||||
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
cy.get(dialogCloseButton).click();
|
||||
closeDialog();
|
||||
});
|
||||
|
||||
it('Unable to create a freeform proposal - when json parent section contains unexpected field', function () {
|
||||
@@ -251,7 +251,7 @@ context(
|
||||
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
cy.get(dialogCloseButton).click();
|
||||
closeDialog();
|
||||
cy.get(rawProposalData)
|
||||
.invoke('val')
|
||||
.should('contain', "i shouldn't be here");
|
||||
@@ -279,7 +279,7 @@ context(
|
||||
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
cy.get(dialogCloseButton).click();
|
||||
closeDialog();
|
||||
});
|
||||
|
||||
// 1005-PROP-009
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
closeDialog,
|
||||
navigateTo,
|
||||
navigation,
|
||||
waitForSpinner,
|
||||
@@ -39,7 +40,6 @@ const maxVoteDeadline = '[data-testid="max-vote"]';
|
||||
const minValidationDeadline = '[data-testid="min-validation"]';
|
||||
const minEnactDeadline = '[data-testid="min-enactment"]';
|
||||
const maxEnactDeadline = '[data-testid="max-enactment"]';
|
||||
const dialogCloseButton = '[data-testid="dialog-close"]';
|
||||
const inputError = '[data-testid="input-error-text"]';
|
||||
const enactmentDeadlineError =
|
||||
'[data-testid="enactment-before-voting-deadline"]';
|
||||
@@ -48,6 +48,7 @@ const feedbackError = '[data-testid="Error"]';
|
||||
const viewProposalBtn = 'view-proposal-btn';
|
||||
const liquidityVoteStatus = 'liquidity-votes-status';
|
||||
const tokenVoteStatus = 'token-votes-status';
|
||||
const proposalTermsSection = 'proposal';
|
||||
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
|
||||
const epochTimeout = Cypress.env('epochTimeout');
|
||||
const proposalTimeout = { timeout: 14000 };
|
||||
@@ -68,7 +69,6 @@ context(
|
||||
{ tags: '@slow' },
|
||||
function () {
|
||||
before('connect wallets and set approval limit', function () {
|
||||
cy.createMarket();
|
||||
cy.visit('/');
|
||||
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||
});
|
||||
@@ -78,6 +78,7 @@ context(
|
||||
waitForSpinner();
|
||||
cy.connectVegaWallet();
|
||||
ethereumWalletConnect();
|
||||
cy.createMarket();
|
||||
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||
navigateTo(navigation.proposals);
|
||||
});
|
||||
@@ -194,7 +195,7 @@ context(
|
||||
'have.text',
|
||||
'Invalid params: proposal_submission.terms.closing_timestamp (cannot be after enactment time)'
|
||||
);
|
||||
cy.get(dialogCloseButton).click();
|
||||
closeDialog();
|
||||
cy.get(minVoteDeadline).click();
|
||||
cy.get(enactmentDeadlineError).should('not.exist');
|
||||
});
|
||||
@@ -286,7 +287,7 @@ context(
|
||||
);
|
||||
});
|
||||
|
||||
// 3001-VOTE-092
|
||||
// 3001-VOTE-092 3004-PMAC-001
|
||||
it('Able to submit update market proposal and vote for proposal', function () {
|
||||
vegaWalletFaucetAssetsWithoutCheck(
|
||||
'fUSDC',
|
||||
@@ -347,8 +348,9 @@ context(
|
||||
|
||||
// 3001-VOTE-026 3001-VOTE-027 3001-VOTE-028 3001-VOTE-095 3001-VOTE-096 3005-PASN-001
|
||||
it('Able to submit new asset proposal using min deadlines', function () {
|
||||
const proposalTitle = 'Test new asset proposal';
|
||||
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||
cy.get(newProposalTitle).type('Test new asset proposal');
|
||||
cy.get(newProposalTitle).type(proposalTitle);
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.fixture('/proposals/new-asset').then((newAssetProposal) => {
|
||||
const newAssetPayload = JSON.stringify(newAssetProposal);
|
||||
@@ -367,7 +369,7 @@ context(
|
||||
cy.contains('Proposal waiting for node vote', proposalTimeout).should(
|
||||
'be.visible'
|
||||
);
|
||||
cy.get(dialogCloseButton).click();
|
||||
closeDialog();
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
// cannot submit a proposal with ERC20 address already in use
|
||||
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
||||
@@ -377,6 +379,17 @@ context(
|
||||
'PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE'
|
||||
);
|
||||
});
|
||||
closeDialog();
|
||||
navigateTo(navigation.proposals);
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil(proposalListItem)
|
||||
.within(() => {
|
||||
cy.getByTestId(viewProposalBtn).click();
|
||||
});
|
||||
cy.getByTestId(proposalTermsSection).within(() => {
|
||||
cy.contains('USDT Coin').should('be.visible');
|
||||
cy.contains('USDT').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('Unable to submit new asset proposal with missing/invalid fields', function () {
|
||||
@@ -415,9 +428,15 @@ context(
|
||||
getProposalInformationFromTable('Proposed enactment') // 3001-VOTE-044
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
// 3001-VOTE-030 3001-VOTE-031
|
||||
cy.getByTestId(proposalTermsSection).within(() => {
|
||||
cy.contains('UpdateAsset').should('be.visible');
|
||||
cy.contains('UpdateERC20').should('be.visible');
|
||||
cy.contains('"lifetimeLimit": "10"').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('Able to submit update asset proposal using max deadline', function () {
|
||||
it.only('Able to submit update asset proposal using max deadline', function () {
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||
enterUpdateAssetProposalDetails();
|
||||
cy.get(maxVoteDeadline).click();
|
||||
|
||||
@@ -25,22 +25,24 @@ import {
|
||||
vegaWalletSetSpecifiedApprovalAmount,
|
||||
vegaWalletTeardown,
|
||||
} from '../../support/wallet-teardown.functions';
|
||||
const stakeValidatorListTotalStake = '[col-id="stake"] > div > span';
|
||||
const stakeValidatorListTotalShare = '[col-id="stakeShare"] > div > span';
|
||||
const stakeValidatorListValidatorStake = '[col-id="stake"] > div > span';
|
||||
const stakeRemoveStakeRadioButton = '[data-testid="remove-stake-radio"]';
|
||||
const stakeTokenAmountInputBox = '[data-testid="token-amount-input"]';
|
||||
const stakeTokenSubmitButton = '[data-testid="token-input-submit-button"]';
|
||||
const stakeAddStakeRadioButton = '[data-testid="add-stake-radio"]';
|
||||
const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]';
|
||||
const totalStake = '[data-testid="total-stake"]';
|
||||
const stakeShare = '[data-testid="stake-percentage"]';
|
||||
const stakeValidatorListTotalStake = 'total-stake';
|
||||
const stakeValidatorListTotalShare = 'total-stake-share';
|
||||
const stakeValidatorListStakePercentage = 'stake-percentage';
|
||||
const userStakeBtn = 'my-stake-btn';
|
||||
const userStake = 'user-stake';
|
||||
const userStakeShare = 'user-stake-share';
|
||||
const viewAllValidatorsToggle = 'validators-view-toggle-all';
|
||||
const viewStakedByMeToggle = 'validators-view-toggle-myStake';
|
||||
const stakeRemoveStakeRadioButton = 'remove-stake-radio';
|
||||
const stakeTokenAmountInputBox = 'token-amount-input';
|
||||
const stakeTokenSubmitButton = 'token-input-submit-button';
|
||||
const stakeAddStakeRadioButton = 'add-stake-radio';
|
||||
const stakeMaximumTokens = 'token-amount-use-maximum';
|
||||
const vegaWalletAssociatedBalance = 'currency-value';
|
||||
const vegaWalletStakedBalances = 'vega-wallet-balance-staked-validators';
|
||||
const ethWalletContainer = 'ethereum-wallet';
|
||||
const vegaWallet = 'vega-wallet';
|
||||
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
|
||||
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
||||
const vegaWalletStakedBalances =
|
||||
'[data-testid="vega-wallet-balance-staked-validators"]';
|
||||
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
|
||||
const vegaWallet = '[data-testid="vega-wallet"]';
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
const epochTimeout = Cypress.env('epochTimeout');
|
||||
|
||||
@@ -91,6 +93,39 @@ context(
|
||||
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
|
||||
});
|
||||
|
||||
it('Able to view validators staked by me', function () {
|
||||
ensureSpecifiedUnstakedTokensAreAssociated('4');
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
clickOnValidatorFromList(0);
|
||||
stakingValidatorPageAddStake('2');
|
||||
closeStakingDialog();
|
||||
navigateTo(navigation.validators);
|
||||
cy.getByTestId(userStake, epochTimeout)
|
||||
.first()
|
||||
.should('have.text', '2.00');
|
||||
cy.getByTestId('total-stake').first().realHover();
|
||||
cy.getByTestId('staked-by-user-tooltip')
|
||||
.first()
|
||||
.should('have.text', 'Staked by me: 2.00');
|
||||
cy.getByTestId('total-pending-stake').first().realHover();
|
||||
cy.getByTestId('pending-user-stake-tooltip')
|
||||
.first()
|
||||
.should('have.text', 'My pending stake: 0.00');
|
||||
cy.getByTestId(userStakeShare).invoke('text').should('not.be.empty'); // Adjust when #3286 is resolved
|
||||
cy.getByTestId(userStakeBtn).should('exist').click();
|
||||
verifyThisEpochValue(2.0);
|
||||
navigateTo(navigation.validators);
|
||||
cy.getByTestId(viewStakedByMeToggle).click();
|
||||
cy.getByTestId(userStakeBtn).should('have.length', 1);
|
||||
cy.getByTestId(viewAllValidatorsToggle).click();
|
||||
clickOnValidatorFromList(1);
|
||||
stakingValidatorPageAddStake('2');
|
||||
closeStakingDialog();
|
||||
navigateTo(navigation.validators);
|
||||
cy.getByTestId(viewStakedByMeToggle).click();
|
||||
cy.getByTestId(userStakeBtn).should('have.length', 2);
|
||||
});
|
||||
|
||||
it('Able to stake against a validator - using vega from vesting contract', function () {
|
||||
stakingPageAssociateTokens('3', { type: 'contract' });
|
||||
verifyUnstakedBalance(3.0);
|
||||
@@ -109,14 +144,13 @@ context(
|
||||
});
|
||||
|
||||
it('Able to stake against a validator - using vega from both wallet and vesting contract', function () {
|
||||
vegaWalletTeardown();
|
||||
stakingPageAssociateTokens('3', { type: 'contract' });
|
||||
navigateTo(navigation.validators);
|
||||
stakingPageAssociateTokens('4', { type: 'wallet' });
|
||||
verifyUnstakedBalance(7.0);
|
||||
verifyEthWalletTotalAssociatedBalance('3.0');
|
||||
verifyEthWalletTotalAssociatedBalance('4.0');
|
||||
verifyEthWalletTotalAssociatedBalance('3.0');
|
||||
verifyEthWalletTotalAssociatedBalance('4.0');
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
clickOnValidatorFromList(0);
|
||||
stakingValidatorPageAddStake('6');
|
||||
@@ -136,7 +170,7 @@ context(
|
||||
clickOnValidatorFromList(0);
|
||||
stakingValidatorPageAddStake('2');
|
||||
verifyUnstakedBalance(3.0);
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
|
||||
.parent()
|
||||
.should('contain', 2.0, txTimeout);
|
||||
closeStakingDialog();
|
||||
@@ -144,36 +178,36 @@ context(
|
||||
clickOnValidatorFromList(1);
|
||||
stakingValidatorPageAddStake('1');
|
||||
verifyUnstakedBalance(2.0);
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
|
||||
.should('have.length', 4, txTimeout)
|
||||
.eq(0)
|
||||
.should('contain', 2.0, txTimeout);
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
|
||||
.eq(1)
|
||||
.should('contain', 1.0, txTimeout);
|
||||
closeStakingDialog();
|
||||
navigateTo(navigation.validators);
|
||||
cy.get(`[row-id="${0}"]`).within(() => {
|
||||
cy.get(stakeValidatorListTotalStake)
|
||||
cy.getByTestId(stakeValidatorListTotalStake)
|
||||
.should('have.text', '2.00')
|
||||
.and('be.visible');
|
||||
cy.get(stakeValidatorListTotalShare)
|
||||
cy.getByTestId(stakeValidatorListTotalShare)
|
||||
.should('have.text', '66.67%')
|
||||
.and('be.visible');
|
||||
cy.get(stakeValidatorListValidatorStake)
|
||||
cy.getByTestId(stakeValidatorListTotalStake)
|
||||
.scrollIntoView()
|
||||
.should('have.text', '2.00')
|
||||
.and('be.visible');
|
||||
});
|
||||
cy.get(`[row-id="${1}"]`).within(() => {
|
||||
cy.get(stakeValidatorListTotalStake)
|
||||
cy.getByTestId(stakeValidatorListTotalStake)
|
||||
.scrollIntoView()
|
||||
.should('have.text', '1.00')
|
||||
.and('be.visible');
|
||||
cy.get(stakeValidatorListTotalShare)
|
||||
cy.getByTestId(stakeValidatorListTotalShare)
|
||||
.should('have.text', '33.33%')
|
||||
.and('be.visible');
|
||||
cy.get(stakeValidatorListValidatorStake)
|
||||
cy.getByTestId(stakeValidatorListTotalStake)
|
||||
.scrollIntoView()
|
||||
.should('have.text', '1.00')
|
||||
.and('be.visible');
|
||||
@@ -203,9 +237,15 @@ context(
|
||||
verifyStakedBalance(2.0);
|
||||
verifyNextEpochValue(2.0);
|
||||
verifyThisEpochValue(2.0);
|
||||
cy.get(totalStake, epochTimeout).should('contain.text', '2');
|
||||
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
|
||||
'contain.text',
|
||||
'2'
|
||||
);
|
||||
waitForBeginningOfEpoch();
|
||||
cy.get(stakeShare).should('have.text', '100%');
|
||||
cy.getByTestId(stakeValidatorListStakePercentage).should(
|
||||
'have.text',
|
||||
'100%'
|
||||
);
|
||||
navigateTo(navigation.validators);
|
||||
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
|
||||
}
|
||||
@@ -227,12 +267,16 @@ context(
|
||||
verifyUnstakedBalance(3.0);
|
||||
verifyNextEpochValue(0.0);
|
||||
verifyThisEpochValue(0.0);
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
||||
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
|
||||
'not.exist',
|
||||
txTimeout
|
||||
);
|
||||
navigateTo(navigation.validators);
|
||||
validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%');
|
||||
|
||||
cy.getByTestId(userStakeBtn).should('not.exist');
|
||||
cy.getByTestId(userStake).should('not.exist');
|
||||
cy.getByTestId(userStakeShare).should('not.exist');
|
||||
});
|
||||
|
||||
it('Unable to remove a stake with a negative value for a validator', function () {
|
||||
@@ -246,10 +290,10 @@ context(
|
||||
closeStakingDialog();
|
||||
navigateTo(navigation.validators);
|
||||
clickOnValidatorFromList(0);
|
||||
cy.get(stakeRemoveStakeRadioButton, txTimeout).click();
|
||||
cy.get(stakeTokenAmountInputBox).type('-0.1');
|
||||
cy.getByTestId(stakeRemoveStakeRadioButton, txTimeout).click();
|
||||
cy.getByTestId(stakeTokenAmountInputBox).type('-0.1');
|
||||
cy.contains('Waiting for next epoch to start', epochTimeout);
|
||||
cy.get(stakeTokenSubmitButton)
|
||||
cy.getByTestId(stakeTokenSubmitButton)
|
||||
.should('be.disabled', epochTimeout)
|
||||
.and('contain', `Remove -0.1 $VEGA tokens at the end of epoch`)
|
||||
.and('be.visible');
|
||||
@@ -266,10 +310,10 @@ context(
|
||||
closeStakingDialog();
|
||||
navigateTo(navigation.validators);
|
||||
clickOnValidatorFromList(0);
|
||||
cy.get(stakeRemoveStakeRadioButton).click();
|
||||
cy.get(stakeTokenAmountInputBox).type('4');
|
||||
cy.getByTestId(stakeRemoveStakeRadioButton).click();
|
||||
cy.getByTestId(stakeTokenAmountInputBox).type('4');
|
||||
cy.contains('Waiting for next epoch to start', epochTimeout);
|
||||
cy.get(stakeTokenSubmitButton)
|
||||
cy.getByTestId(stakeTokenSubmitButton)
|
||||
.should('be.disabled', epochTimeout)
|
||||
.and('contain', `Remove 4 $VEGA tokens at the end of epoch`)
|
||||
.and('be.visible');
|
||||
@@ -285,17 +329,17 @@ context(
|
||||
verifyStakedBalance(2.0);
|
||||
closeStakingDialog();
|
||||
stakingPageDisassociateAllTokens();
|
||||
cy.get(ethWalletContainer).within(() => {
|
||||
cy.getByTestId(ethWalletContainer).within(() => {
|
||||
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
|
||||
});
|
||||
verifyEthWalletTotalAssociatedBalance('0.0');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
cy.getByTestId(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'0.00'
|
||||
);
|
||||
});
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
||||
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
|
||||
'not.exist',
|
||||
txTimeout
|
||||
);
|
||||
@@ -313,17 +357,17 @@ context(
|
||||
verifyStakedBalance(2.0);
|
||||
closeStakingDialog();
|
||||
stakingPageDisassociateAllTokens('contract');
|
||||
cy.get(ethWalletContainer).within(() => {
|
||||
cy.getByTestId(ethWalletContainer).within(() => {
|
||||
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
|
||||
});
|
||||
verifyEthWalletTotalAssociatedBalance('0.0');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
cy.getByTestId(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'0.00'
|
||||
);
|
||||
});
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
||||
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
|
||||
'not.exist',
|
||||
txTimeout
|
||||
);
|
||||
@@ -342,8 +386,8 @@ context(
|
||||
closeStakingDialog();
|
||||
stakingPageDisassociateTokens('1');
|
||||
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
cy.getByTestId(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'2.00'
|
||||
);
|
||||
@@ -409,8 +453,8 @@ context(
|
||||
verifyUnstakedBalance(0.0);
|
||||
closeStakingDialog();
|
||||
stakingPageAssociateTokens('6');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
cy.getByTestId(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'12.00'
|
||||
);
|
||||
@@ -429,9 +473,12 @@ context(
|
||||
verifyUnstakedBalance(1.0);
|
||||
closeStakingDialog();
|
||||
clickOnValidatorFromList(0);
|
||||
cy.get(stakeAddStakeRadioButton).click();
|
||||
cy.get(stakeMaximumTokens, { timeout: 60000 }).click();
|
||||
cy.get(stakeTokenSubmitButton).should('contain', 'Add 1 $VEGA tokens');
|
||||
cy.getByTestId(stakeAddStakeRadioButton).click();
|
||||
cy.getByTestId(stakeMaximumTokens, { timeout: 60000 }).click();
|
||||
cy.getByTestId(stakeTokenSubmitButton).should(
|
||||
'contain',
|
||||
'Add 1 $VEGA tokens'
|
||||
);
|
||||
});
|
||||
|
||||
afterEach('Teardown Wallet', function () {
|
||||
|
||||
@@ -183,6 +183,7 @@ context(
|
||||
// 1004-ASSO-018
|
||||
// 1004-ASSO-024
|
||||
// 1004-ASSO-023
|
||||
// 1004-ASSO-032
|
||||
|
||||
stakingPageAssociateTokens('2', {
|
||||
type: 'contract',
|
||||
|
||||
@@ -6,159 +6,203 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
cy.get('nav', { timeout: 10000 }).should('be.visible');
|
||||
});
|
||||
|
||||
describe('with wallets disconnected', function () {
|
||||
describe('Links and buttons', function () {
|
||||
it('should have link for proposal page', function () {
|
||||
cy.getByTestId('home-proposals').within(() => {
|
||||
cy.get('[href="/proposals"]')
|
||||
.should('exist')
|
||||
.and('have.text', 'Browse, vote, and propose');
|
||||
});
|
||||
});
|
||||
it('should show open or enacted proposals with proposal summary', function () {
|
||||
cy.get('body').then(($body) => {
|
||||
if (!$body.find('[data-testid="proposals-list-item"]').length) {
|
||||
cy.createMarket();
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
}
|
||||
});
|
||||
cy.getByTestId('proposals-list-item')
|
||||
.should('have.length.at.least', 1)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getByTestId('proposal-title')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('proposal-type')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('proposal-description')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('proposal-details')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('proposal-status')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('vote-details')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('view-proposal-btn').should('be.visible');
|
||||
});
|
||||
});
|
||||
it('should have external link for governance', function () {
|
||||
cy.getByTestId('home-proposals').within(() => {
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://vega.xyz/governance');
|
||||
});
|
||||
});
|
||||
it('should have link for validator page', function () {
|
||||
cy.getByTestId('home-validators').within(() => {
|
||||
cy.get('[href="/validators"]')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'Browse, and stake');
|
||||
});
|
||||
});
|
||||
it('should have external link for validators', function () {
|
||||
cy.getByTestId('home-validators').within(() => {
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
.and(
|
||||
'contain',
|
||||
'https://community.vega.xyz/c/mainnet-validator-candidates'
|
||||
);
|
||||
});
|
||||
});
|
||||
it('should have information on active nodes', function () {
|
||||
cy.getByTestId('node-information')
|
||||
.first()
|
||||
.should('contain.text', '2')
|
||||
.and('contain.text', 'active nodes');
|
||||
});
|
||||
it('should have information on consensus nodes', function () {
|
||||
cy.getByTestId('node-information')
|
||||
.last()
|
||||
.should('contain.text', '2')
|
||||
.and('contain.text', 'consensus nodes');
|
||||
});
|
||||
it('should contain link to specific validators', function () {
|
||||
cy.getByTestId('validators')
|
||||
.should('have.length', '2')
|
||||
.each(($validator) => {
|
||||
cy.wrap($validator).find('a').should('have.attr', 'href');
|
||||
});
|
||||
});
|
||||
it('should have link for rewards page', function () {
|
||||
cy.getByTestId('home-rewards').within(() => {
|
||||
cy.get('[href="/rewards"]')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'See rewards');
|
||||
});
|
||||
});
|
||||
it('should have link for withdrawal page', function () {
|
||||
cy.getByTestId('home-vega-token').within(() => {
|
||||
cy.get('[href="/token/withdraw"]')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'Manage tokens');
|
||||
});
|
||||
describe('Links and buttons', function () {
|
||||
it('should have link for proposal page', function () {
|
||||
cy.getByTestId('home-proposals').within(() => {
|
||||
cy.get('[href="/proposals"]')
|
||||
.should('exist')
|
||||
.and('have.text', 'Browse, vote, and propose');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mobile view - navigation bar', function () {
|
||||
before('Change to mobile resolution', function () {
|
||||
cy.viewport('iphone-xr');
|
||||
});
|
||||
|
||||
it('should have burger button', () => {
|
||||
cy.getByTestId('button-menu-drawer').should('be.visible').click();
|
||||
cy.getByTestId('menu-drawer').should('be.visible');
|
||||
});
|
||||
|
||||
it('should have link for proposal page', function () {
|
||||
cy.getByTestId('menu-drawer').within(() => {
|
||||
cy.get('[href="/proposals"]')
|
||||
.should('exist')
|
||||
.and('have.text', 'Proposals');
|
||||
it('should display announcement banner', function () {
|
||||
cy.getByTestId('app-announcement')
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
cy.getByTestId('external-link').should('exist');
|
||||
});
|
||||
cy.getByTestId('app-announcement-close').should('be.visible').click();
|
||||
cy.getByTestId('app-announcement').should('not.exist');
|
||||
});
|
||||
|
||||
it('should show open or enacted proposals with proposal summary', function () {
|
||||
cy.get('body').then(($body) => {
|
||||
if (!$body.find('[data-testid="proposals-list-item"]').length) {
|
||||
cy.createMarket();
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
}
|
||||
});
|
||||
it('should have link for validator page', function () {
|
||||
cy.getByTestId('menu-drawer').within(() => {
|
||||
cy.get('[href="/validators"]')
|
||||
cy.getByTestId('proposals-list-item')
|
||||
.should('have.length.at.least', 1)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getByTestId('proposal-title')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('proposal-type').invoke('text').should('not.be.empty');
|
||||
cy.getByTestId('proposal-description')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('proposal-details')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('proposal-status')
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId('vote-details').invoke('text').should('not.be.empty');
|
||||
cy.getByTestId('view-proposal-btn').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have external link for governance', function () {
|
||||
cy.getByTestId('home-proposals').within(() => {
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://vega.xyz/governance');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have link for validator page', function () {
|
||||
cy.getByTestId('home-validators').within(() => {
|
||||
cy.get('[href="/validators"]')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'Browse, and stake');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have external link for validators', function () {
|
||||
cy.getByTestId('home-validators').within(() => {
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
.and(
|
||||
'contain',
|
||||
'https://community.vega.xyz/c/mainnet-validator-candidates'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have information on active nodes', function () {
|
||||
cy.getByTestId('node-information')
|
||||
.first()
|
||||
.should('contain.text', '2')
|
||||
.and('contain.text', 'active nodes');
|
||||
});
|
||||
|
||||
it('should have information on consensus nodes', function () {
|
||||
cy.getByTestId('node-information')
|
||||
.last()
|
||||
.should('contain.text', '2')
|
||||
.and('contain.text', 'consensus nodes');
|
||||
});
|
||||
|
||||
it('should contain link to specific validators', function () {
|
||||
cy.getByTestId('validators')
|
||||
.should('have.length', '2')
|
||||
.each(($validator) => {
|
||||
cy.wrap($validator).find('a').should('have.attr', 'href');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have link for rewards page', function () {
|
||||
cy.getByTestId('home-rewards').within(() => {
|
||||
cy.get('[href="/rewards"]')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'See rewards');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have link for withdrawal page', function () {
|
||||
cy.getByTestId('home-vega-token').within(() => {
|
||||
cy.get('[href="/token/withdraw"]')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'Manage tokens');
|
||||
});
|
||||
});
|
||||
|
||||
it('should display network data', function () {
|
||||
cy.getByTestId('git-network-data')
|
||||
.should('contain.text', 'Reading network data from')
|
||||
.within(() => {
|
||||
cy.get('span')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'Validators');
|
||||
.should('have.text', 'http://localhost:3028/query');
|
||||
cy.getByTestId('link').should('exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should have link for rewards page', function () {
|
||||
cy.getByTestId('menu-drawer').within(() => {
|
||||
cy.get('[href="/rewards"]')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'Rewards');
|
||||
it('should display eth data', function () {
|
||||
cy.getByTestId('git-eth-data')
|
||||
.should('contain.text', 'Reading Ethereum data from')
|
||||
.within(() => {
|
||||
cy.get('span').should('have.text', 'http://localhost:8545');
|
||||
});
|
||||
});
|
||||
it('should have link for withdrawal page', function () {
|
||||
cy.getByTestId('menu-drawer').within(() => {
|
||||
cy.get('[href="/token/withdraw"]')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'Withdraw');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
after(function () {
|
||||
cy.viewport(
|
||||
Cypress.config('viewportWidth'),
|
||||
Cypress.config('viewportHeight')
|
||||
);
|
||||
it('should contain link for known issues on Github', function () {
|
||||
cy.getByTestId('git-info').within(() => {
|
||||
cy.contains('Known issues and feedback on')
|
||||
.find('[data-testid="link"]')
|
||||
.should(
|
||||
'have.attr',
|
||||
'href',
|
||||
'https://github.com/vegaprotocol/feedback/discussions'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mobile view - navigation bar', function () {
|
||||
before('Change to mobile resolution', function () {
|
||||
cy.viewport('iphone-xr');
|
||||
});
|
||||
|
||||
it('should have burger button', () => {
|
||||
cy.getByTestId('button-menu-drawer').should('be.visible').click();
|
||||
cy.getByTestId('menu-drawer').should('be.visible');
|
||||
});
|
||||
|
||||
it('should have link for proposal page', function () {
|
||||
cy.getByTestId('menu-drawer').within(() => {
|
||||
cy.get('[href="/proposals"]')
|
||||
.should('exist')
|
||||
.and('have.text', 'Proposals');
|
||||
});
|
||||
});
|
||||
it('should have link for validator page', function () {
|
||||
cy.getByTestId('menu-drawer').within(() => {
|
||||
cy.get('[href="/validators"]')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'Validators');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have link for rewards page', function () {
|
||||
cy.getByTestId('menu-drawer').within(() => {
|
||||
cy.get('[href="/rewards"]')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'Rewards');
|
||||
});
|
||||
});
|
||||
it('should have link for withdrawal page', function () {
|
||||
cy.getByTestId('menu-drawer').within(() => {
|
||||
cy.get('[href="/token/withdraw"]')
|
||||
.first()
|
||||
.should('exist')
|
||||
.and('have.text', 'Withdraw');
|
||||
});
|
||||
});
|
||||
|
||||
after(function () {
|
||||
cy.viewport(
|
||||
Cypress.config('viewportWidth'),
|
||||
Cypress.config('viewportHeight')
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,19 +26,19 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
|
||||
cy.connectPublicKey(vegaWalletPubKey);
|
||||
});
|
||||
|
||||
it('Able to connect public key via wallet', function () {
|
||||
verifyConnectedToPubKey();
|
||||
cy.getByTestId('currency-title', { timeout: 10000 })
|
||||
.should('have.length.at.least', 4)
|
||||
.and('contain.text', 'USDC (fake)');
|
||||
});
|
||||
|
||||
it('Able to connect public key using url', function () {
|
||||
cy.getByTestId('exit-view').click();
|
||||
cy.visit(`/?address=${vegaWalletPubKey}`);
|
||||
verifyConnectedToPubKey();
|
||||
});
|
||||
|
||||
it('Able to connect public key via wallet and view assets in wallet', function () {
|
||||
verifyConnectedToPubKey();
|
||||
cy.getByTestId('currency-title', { timeout: 10000 })
|
||||
.should('have.length.at.least', 4)
|
||||
.and('contain.text', 'USDC (fake)');
|
||||
});
|
||||
|
||||
it('Unable to submit proposal with public key', function () {
|
||||
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ context('Validators Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
it('Should be able to see validator stake', function () {
|
||||
cy.get('[col-id="stake"] > div > span > span')
|
||||
cy.getByTestId('total-stake')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($stake) => {
|
||||
cy.wrap($stake).should('not.be.empty');
|
||||
@@ -82,7 +82,7 @@ context('Validators Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
it('Should be able to see validator stake tooltip', function () {
|
||||
cy.get('[col-id="stake"] > div > span > span').first().realHover();
|
||||
cy.getByTestId('total-stake').first().realHover();
|
||||
|
||||
cy.get(stakedByOperatorToolTip)
|
||||
.invoke('text')
|
||||
@@ -96,17 +96,15 @@ context('Validators Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
it('Should be able to see validator normalised voting power', function () {
|
||||
cy.get('[col-id="normalisedVotingPower"] > div > span > span')
|
||||
cy.getByTestId('normalised-voting-power')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($vPower) => {
|
||||
cy.wrap($vPower).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator voting power tooltip', function () {
|
||||
cy.get('[col-id="normalisedVotingPower"] > div > span > span')
|
||||
.first()
|
||||
.realHover();
|
||||
it('Should be able to see validator normalised voting power tooltip', function () {
|
||||
cy.getByTestId('normalised-voting-power').first().realHover();
|
||||
|
||||
cy.get(unnormalisedVotingPowerToolTip)
|
||||
.invoke('text')
|
||||
@@ -118,7 +116,7 @@ context('Validators Page - verify elements on page', function () {
|
||||
|
||||
// 2002-SINC-018
|
||||
it('Should be able to see validator total penalties', function () {
|
||||
cy.get('[col-id="totalPenalties"] > div > span > span')
|
||||
cy.getByTestId('total-penalty')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($penalties) => {
|
||||
cy.wrap($penalties).should('contain.text', '0%');
|
||||
@@ -126,7 +124,7 @@ context('Validators Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
it('Should be able to see validator penalties tooltip', function () {
|
||||
cy.get('[col-id="totalPenalties"] > div > span > span').realHover();
|
||||
cy.getByTestId('total-penalty').realHover();
|
||||
|
||||
cy.get(performancePenaltyToolTip)
|
||||
.invoke('text')
|
||||
@@ -140,7 +138,7 @@ context('Validators Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
it('Should be able to see validator pending stake', function () {
|
||||
cy.get('[col-id="pendingStake"] > div > span')
|
||||
cy.getByTestId('total-pending-stake')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($pendingStake) => {
|
||||
cy.wrap($pendingStake).should('contain.text', '0.00');
|
||||
|
||||
@@ -84,3 +84,7 @@ export function verifyEthWalletAssociatedBalance(amount: string) {
|
||||
.parent(txTimeout)
|
||||
.should('contain', amount, txTimeout);
|
||||
}
|
||||
|
||||
export function closeDialog() {
|
||||
cy.getByTestId('dialog-close').click();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { navigateTo, navigation } from './common.functions';
|
||||
import { closeDialog, navigateTo, navigation } from './common.functions';
|
||||
import { ensureSpecifiedUnstakedTokensAreAssociated } from './staking.functions';
|
||||
|
||||
const newProposalButton = '[data-testid="new-proposal-link"]';
|
||||
@@ -12,7 +12,6 @@ const voteButtons = '[data-testid="vote-buttons"]';
|
||||
const dialogTitle = '[data-testid="dialog-title"]';
|
||||
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
|
||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||
const dialogCloseButton = '[data-testid="dialog-close"]';
|
||||
const epochTimeout = Cypress.env('epochTimeout');
|
||||
const proposalTimeout = { timeout: 14000 };
|
||||
|
||||
@@ -125,7 +124,7 @@ export function voteForProposal(vote: string) {
|
||||
'have.text',
|
||||
'Transaction complete'
|
||||
);
|
||||
cy.get(dialogCloseButton).click();
|
||||
closeDialog();
|
||||
}
|
||||
|
||||
export function waitForProposalSync() {
|
||||
@@ -176,7 +175,7 @@ export function waitForProposalSubmitted() {
|
||||
'be.visible'
|
||||
);
|
||||
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
|
||||
cy.get(dialogCloseButton).click();
|
||||
closeDialog();
|
||||
}
|
||||
|
||||
export function createRawProposal(proposerBalance?: string) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { closeDialog } from './common.functions';
|
||||
import { vegaWalletTeardown } from './wallet-teardown.functions';
|
||||
|
||||
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
|
||||
@@ -14,11 +15,10 @@ const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
|
||||
const associateContractRadioButton = '[data-testid="associate-radio-contract"]';
|
||||
const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]';
|
||||
const stakeValidatorListPendingStake = '[col-id="pendingStake"]';
|
||||
const stakeValidatorListTotalStake = '[col-id="stake"] > div > span';
|
||||
const stakeValidatorListTotalShare = '[col-id="stakeShare"] > div > span';
|
||||
const stakeValidatorListTotalStake = 'total-stake';
|
||||
const stakeValidatorListTotalShare = 'total-stake-share';
|
||||
const stakeValidatorListName = '[col-id="validator"]';
|
||||
const vegaKeySelector = '#vega-key-selector';
|
||||
const dialogCloseButton = '[data-testid="dialog-close"]';
|
||||
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
const epochTimeout = Cypress.env('epochTimeout');
|
||||
@@ -54,7 +54,7 @@ export function stakingValidatorPageRemoveStake(stake: string) {
|
||||
.and('contain', `Remove ${stake} $VEGA tokens at the end of epoch`)
|
||||
.and('be.visible')
|
||||
.click();
|
||||
cy.get(dialogCloseButton).click();
|
||||
closeDialog();
|
||||
}
|
||||
|
||||
export function stakingPageAssociateTokens(
|
||||
@@ -185,11 +185,11 @@ export function validateValidatorListTotalStakeAndShare(
|
||||
cy.contains('Loading...', epochTimeout).should('not.exist');
|
||||
waitForBeginningOfEpoch();
|
||||
cy.get(`[row-id="${positionOnList}"]`).within(() => {
|
||||
cy.get(stakeValidatorListTotalStake, epochTimeout).should(
|
||||
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
|
||||
'have.text',
|
||||
expectedTotalStake
|
||||
);
|
||||
cy.get(stakeValidatorListTotalShare, epochTimeout).should(
|
||||
cy.getByTestId(stakeValidatorListTotalShare, epochTimeout).should(
|
||||
'have.text',
|
||||
expectedTotalShare
|
||||
);
|
||||
|
||||
@@ -73,9 +73,6 @@ export async function vegaWalletTeardown() {
|
||||
}
|
||||
});
|
||||
cy.get(vegaWalletContainer).within(() => {
|
||||
cy.getByTestId('vega-wallet-balance-staked-validators', {
|
||||
timeout: transactionTimeout,
|
||||
}).should('not.exist');
|
||||
cy.getByTestId('associated-amount', {
|
||||
timeout: transactionTimeout,
|
||||
}).contains('0.00', {
|
||||
@@ -125,6 +122,9 @@ async function vegaWalletTeardownVesting(vestingContract: TokenVesting) {
|
||||
log: false,
|
||||
}).then((vestingAmount) => {
|
||||
if (Number(vestingAmount) != 0) {
|
||||
// Wait needed to allow time for ganache to process tx for stakingBridgeContract.remove_stake
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(1000);
|
||||
cy.wrap(
|
||||
vestingContract.remove_stake(String(vestingAmount), vegaWalletPubKey),
|
||||
{ timeout: transactionTimeout, log: false }
|
||||
|
||||
@@ -13,6 +13,7 @@ NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
||||
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND=false
|
||||
|
||||
@@ -5,6 +5,7 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_FAIRGROUND=false
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_CONFIG_URL=''
|
||||
|
||||
NX_VEGA_URL=http://localhost:3028/query
|
||||
|
||||
@@ -10,3 +10,4 @@ NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
@@ -11,3 +11,4 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_ENV=MIRROR
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
|
||||
NX_VEGA_URL=https://api.n00.mainnet-mirror.vega.xyz/graphql
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_VEGA_EXPLORER_URL=https://mirror.explorer.vega.xyz
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
@@ -1,8 +0,0 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_URL=https://api.sandbox.vega.xyz/graphql
|
||||
NX_VEGA_ENV=SANDBOX
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","STAGNET1":"https://stagnet1.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/sandbox/vegawallet-sandbox.toml
|
||||
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
@@ -7,3 +7,4 @@ NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
@@ -8,3 +8,4 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
@@ -11,3 +11,4 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
|
||||
@@ -8,3 +8,4 @@ NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import {
|
||||
ViewingAsBanner,
|
||||
AnnouncementBanner,
|
||||
ExternalLink,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
|
||||
import { AnnouncementBanner } from '@vegaprotocol/announcements';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import React from 'react';
|
||||
|
||||
@@ -15,18 +12,16 @@ export interface TemplateSidebarProps {
|
||||
}
|
||||
|
||||
export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
|
||||
const { VEGA_ENV } = useEnvironment();
|
||||
const { VEGA_ENV, ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
|
||||
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
|
||||
return (
|
||||
<>
|
||||
<AnnouncementBanner>
|
||||
<div className="font-alpha calt uppercase text-center text-lg text-white">
|
||||
<span className="pr-4">Wait no longer, SIM3 is here!</span>
|
||||
<ExternalLink href="https://fairground.wtf/sim3">
|
||||
Learn more
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</AnnouncementBanner>
|
||||
{ANNOUNCEMENTS_CONFIG_URL && (
|
||||
<AnnouncementBanner
|
||||
app="governance"
|
||||
configUrl={ANNOUNCEMENTS_CONFIG_URL}
|
||||
/>
|
||||
)}
|
||||
<Nav theme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'} />
|
||||
{isReadOnly ? (
|
||||
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
|
||||
|
||||
@@ -12,6 +12,7 @@ const TRUTHY = ['1', 'true'];
|
||||
interface VegaContracts {
|
||||
claimAddress: string;
|
||||
lockedAddress: string;
|
||||
tokenVestingAddress?: string;
|
||||
}
|
||||
|
||||
const customClaimAddress = process.env['NX_CUSTOM_CLAIM_ADDRESS'] as string;
|
||||
@@ -36,21 +37,16 @@ export const ContractAddresses: {
|
||||
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
|
||||
lockedAddress: '0x0', // TODO not deployed to this env
|
||||
},
|
||||
SANDBOX: {
|
||||
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
|
||||
lockedAddress: '0x0', // TODO not deployed to this env
|
||||
},
|
||||
TESTNET: {
|
||||
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
|
||||
lockedAddress: '0x0', // TODO not deployed to this env
|
||||
},
|
||||
MIRROR: {
|
||||
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
|
||||
lockedAddress: '0x0', // TODO not deployed to this env
|
||||
},
|
||||
VALIDATOR_TESTNET: {
|
||||
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
|
||||
lockedAddress: '0x0', // TODO not deployed to this env
|
||||
// This is a fallback contract address for the validator testnet network which does not
|
||||
// have a vesting contract address set and is therefore not in the ethereum config
|
||||
tokenVestingAddress: '0xadFcb7f93a24F8743a8e548d74d2ecB373c92866',
|
||||
},
|
||||
MAINNET: {
|
||||
claimAddress: '0x0ee1fb382caf98e86e97e51f9f42f8b4654020f3',
|
||||
|
||||
@@ -49,6 +49,13 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
|
||||
signer = provider.getSigner();
|
||||
}
|
||||
|
||||
const tokenVestingAddress =
|
||||
config.token_vesting_contract?.address ||
|
||||
ENV.addresses.tokenVestingAddress;
|
||||
if (!tokenVestingAddress) {
|
||||
throw new Error('No token vesting address found');
|
||||
}
|
||||
|
||||
if (provider && config) {
|
||||
const staking = new StakingBridge(
|
||||
config.staking_bridge_contract.address,
|
||||
@@ -63,7 +70,7 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
|
||||
signer || provider
|
||||
),
|
||||
vesting: new TokenVesting(
|
||||
config.token_vesting_contract.address,
|
||||
tokenVestingAddress,
|
||||
signer || provider
|
||||
),
|
||||
claim: new Claim(ENV.addresses.claimAddress, signer || provider),
|
||||
|
||||
@@ -602,11 +602,14 @@
|
||||
"noValidators": "No validators",
|
||||
"validator": "Validator",
|
||||
"stake": "Stake",
|
||||
"myStake": "My stake",
|
||||
"stakeShare": "Stake share",
|
||||
"stakedByOperator": "Staked by operator",
|
||||
"stakedByDelegates": "Staked by delegates",
|
||||
"stakedByMe": "Staked by me",
|
||||
"totalStake": "Total stake",
|
||||
"pendingStake": "Pending stake",
|
||||
"myPendingStake": "My pending stake",
|
||||
"totalPenalties": "Total penalties",
|
||||
"noPenaltyDataFromLastEpoch": "No penalty data from last epoch",
|
||||
"stakeNeededForPromotion": "Stake needed for promotion",
|
||||
|
||||
@@ -12,14 +12,14 @@ import { useRefreshAfterEpoch } from '../../hooks/use-refresh-after-epoch';
|
||||
import { ProposalsListItem } from '../proposals/components/proposals-list-item';
|
||||
import Routes from '../routes';
|
||||
import { ExternalLinks, removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
import { useNodesQuery } from '../staking/home/__generated___/Nodes';
|
||||
import { useNodesQuery } from '../staking/home/__generated__/Nodes';
|
||||
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
|
||||
import { getNotRejectedProposals } from '../proposals/proposals/proposals-container';
|
||||
import { Heading } from '../../components/heading';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { RouteChildProps } from '..';
|
||||
import type { ProposalFieldsFragment } from '../proposals/proposals/__generated__/Proposals';
|
||||
import type { NodesFragmentFragment } from '../staking/home/__generated___/Nodes';
|
||||
import type { NodesFragmentFragment } from '../staking/home/__generated__/Nodes';
|
||||
|
||||
const nodesToShow = 6;
|
||||
|
||||
|
||||
@@ -16,12 +16,8 @@ import orderBy from 'lodash/orderBy';
|
||||
const orderByDate = (arr: ProposalFieldsFragment[]) =>
|
||||
orderBy(
|
||||
arr,
|
||||
[
|
||||
(p) => new Date(p?.terms?.enactmentDatetime || 0).getTime(), // has to be defaulted to 0 because new Date(null).getTime() -> NaN which is first when ordered.
|
||||
(p) => new Date(p?.terms?.closingDatetime).getTime(),
|
||||
(p) => p.id,
|
||||
],
|
||||
['desc', 'desc', 'desc']
|
||||
[(p) => new Date(p?.terms?.closingDatetime).getTime(), (p) => p.id],
|
||||
['desc', 'desc']
|
||||
);
|
||||
|
||||
export function getNotRejectedProposals<T extends ProposalFieldsFragment>(
|
||||
|
||||
+6
@@ -21,6 +21,12 @@ export const EpochIndividualRewards = () => {
|
||||
first: Number(delegationsPagination),
|
||||
}
|
||||
: undefined,
|
||||
// we can use the same value for rewardsPagination as delegationsPagination
|
||||
rewardsPagination: delegationsPagination
|
||||
? {
|
||||
first: Number(delegationsPagination),
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
skip: !pubKey,
|
||||
});
|
||||
|
||||
@@ -21,10 +21,14 @@ fragment DelegationFields on Delegation {
|
||||
epoch
|
||||
}
|
||||
|
||||
query Rewards($partyId: ID!, $delegationsPagination: Pagination) {
|
||||
query Rewards(
|
||||
$partyId: ID!
|
||||
$delegationsPagination: Pagination
|
||||
$rewardsPagination: Pagination
|
||||
) {
|
||||
party(id: $partyId) {
|
||||
id
|
||||
rewardsConnection {
|
||||
rewardsConnection(pagination: $rewardsPagination) {
|
||||
edges {
|
||||
node {
|
||||
...RewardFields
|
||||
|
||||
@@ -10,6 +10,7 @@ export type DelegationFieldsFragment = { __typename?: 'Delegation', amount: stri
|
||||
export type RewardsQueryVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
delegationsPagination?: Types.InputMaybe<Types.Pagination>;
|
||||
rewardsPagination?: Types.InputMaybe<Types.Pagination>;
|
||||
}>;
|
||||
|
||||
|
||||
@@ -75,10 +76,10 @@ export const EpochFieldsFragmentDoc = gql`
|
||||
}
|
||||
`;
|
||||
export const RewardsDocument = gql`
|
||||
query Rewards($partyId: ID!, $delegationsPagination: Pagination) {
|
||||
query Rewards($partyId: ID!, $delegationsPagination: Pagination, $rewardsPagination: Pagination) {
|
||||
party(id: $partyId) {
|
||||
id
|
||||
rewardsConnection {
|
||||
rewardsConnection(pagination: $rewardsPagination) {
|
||||
edges {
|
||||
node {
|
||||
...RewardFields
|
||||
@@ -119,6 +120,7 @@ ${DelegationFieldsFragmentDoc}`;
|
||||
* variables: {
|
||||
* partyId: // value for 'partyId'
|
||||
* delegationsPagination: // value for 'delegationsPagination'
|
||||
* rewardsPagination: // value for 'rewardsPagination'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
|
||||
@@ -104,7 +104,7 @@ export const RewardsPage = () => {
|
||||
</section>
|
||||
)}
|
||||
|
||||
<section className="grid xl:grid-cols-2 gap-12 items-center mb-8">
|
||||
<section className="grid xl:grid-cols-[1fr_auto] gap-12 items-center mb-8">
|
||||
<div>
|
||||
<SubHeading title={t('rewardsAndFeesReceived')} />
|
||||
<p>
|
||||
@@ -114,7 +114,7 @@ export const RewardsPage = () => {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="max-w-[600px]">
|
||||
<div className="w-[440px]">
|
||||
<Toggle
|
||||
name="epoch-reward-view-toggle"
|
||||
toggles={[
|
||||
|
||||
@@ -7,9 +7,10 @@ query PreviousEpoch($epochId: ID) {
|
||||
id
|
||||
rewardScore {
|
||||
rawValidatorScore
|
||||
performanceScore
|
||||
}
|
||||
rankingScore {
|
||||
performanceScore
|
||||
stakeScore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-5
@@ -23,6 +23,17 @@ fragment StakingNodeFields on Node {
|
||||
}
|
||||
}
|
||||
|
||||
fragment StakingDelegationFields on Delegation {
|
||||
amount
|
||||
epoch
|
||||
node {
|
||||
id
|
||||
}
|
||||
party {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
query Staking($partyId: ID!, $delegationsPagination: Pagination) {
|
||||
party(id: $partyId) {
|
||||
id
|
||||
@@ -32,11 +43,7 @@ query Staking($partyId: ID!, $delegationsPagination: Pagination) {
|
||||
delegationsConnection(pagination: $delegationsPagination) {
|
||||
edges {
|
||||
node {
|
||||
amount
|
||||
epoch
|
||||
node {
|
||||
id
|
||||
}
|
||||
...StakingDelegationFields
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ export type PreviousEpochQueryVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type PreviousEpochQuery = { __typename?: 'Query', epoch: { __typename?: 'Epoch', id: string, validatorsConnection?: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, rewardScore?: { __typename?: 'RewardScore', rawValidatorScore: string } | null, rankingScore: { __typename?: 'RankingScore', performanceScore: string } } } | null> | null } | null } };
|
||||
export type PreviousEpochQuery = { __typename?: 'Query', epoch: { __typename?: 'Epoch', id: string, validatorsConnection?: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, rewardScore?: { __typename?: 'RewardScore', rawValidatorScore: string, performanceScore: string } | null, rankingScore: { __typename?: 'RankingScore', stakeScore: string } } } | null> | null } | null } };
|
||||
|
||||
|
||||
export const PreviousEpochDocument = gql`
|
||||
@@ -21,9 +21,10 @@ export const PreviousEpochDocument = gql`
|
||||
id
|
||||
rewardScore {
|
||||
rawValidatorScore
|
||||
performanceScore
|
||||
}
|
||||
rankingScore {
|
||||
performanceScore
|
||||
stakeScore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-7
@@ -5,13 +5,15 @@ import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type StakingNodeFieldsFragment = { __typename?: 'Node', id: string, name: string, pubkey: string, infoUrl: string, location: string, ethereumAddress: string, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null, rankingScore: { __typename?: 'RankingScore', rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string, status: Types.ValidatorStatus } };
|
||||
|
||||
export type StakingDelegationFieldsFragment = { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string }, party: { __typename?: 'Party', id: string } };
|
||||
|
||||
export type StakingQueryVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
delegationsPagination?: Types.InputMaybe<Types.Pagination>;
|
||||
}>;
|
||||
|
||||
|
||||
export type StakingQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string }, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string } } } | null> | null } | null } | null, epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } }, nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, pubkey: string, infoUrl: string, location: string, ethereumAddress: string, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null, rankingScore: { __typename?: 'RankingScore', rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string, status: Types.ValidatorStatus } } } | null> | null }, nodeData?: { __typename?: 'NodeData', stakedTotal: string, totalNodes: number, inactiveNodes: number, uptime: number } | null };
|
||||
export type StakingQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string }, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string }, party: { __typename?: 'Party', id: string } } } | null> | null } | null } | null, epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } }, nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, pubkey: string, infoUrl: string, location: string, ethereumAddress: string, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null, rankingScore: { __typename?: 'RankingScore', rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string, status: Types.ValidatorStatus } } } | null> | null }, nodeData?: { __typename?: 'NodeData', stakedTotal: string, totalNodes: number, inactiveNodes: number, uptime: number } | null };
|
||||
|
||||
export const StakingNodeFieldsFragmentDoc = gql`
|
||||
fragment StakingNodeFields on Node {
|
||||
@@ -39,6 +41,18 @@ export const StakingNodeFieldsFragmentDoc = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const StakingDelegationFieldsFragmentDoc = gql`
|
||||
fragment StakingDelegationFields on Delegation {
|
||||
amount
|
||||
epoch
|
||||
node {
|
||||
id
|
||||
}
|
||||
party {
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const StakingDocument = gql`
|
||||
query Staking($partyId: ID!, $delegationsPagination: Pagination) {
|
||||
party(id: $partyId) {
|
||||
@@ -49,11 +63,7 @@ export const StakingDocument = gql`
|
||||
delegationsConnection(pagination: $delegationsPagination) {
|
||||
edges {
|
||||
node {
|
||||
amount
|
||||
epoch
|
||||
node {
|
||||
id
|
||||
}
|
||||
...StakingDelegationFields
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,7 +90,8 @@ export const StakingDocument = gql`
|
||||
uptime
|
||||
}
|
||||
}
|
||||
${StakingNodeFieldsFragmentDoc}`;
|
||||
${StakingDelegationFieldsFragmentDoc}
|
||||
${StakingNodeFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useStakingQuery__
|
||||
@@ -1,106 +0,0 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type PreviousEpochQueryVariables = Types.Exact<{
|
||||
epochId?: Types.InputMaybe<Types.Scalars['ID']>;
|
||||
}>;
|
||||
|
||||
export type PreviousEpochQuery = {
|
||||
__typename?: 'Query';
|
||||
epoch: {
|
||||
__typename?: 'Epoch';
|
||||
id: string;
|
||||
validatorsConnection?: {
|
||||
__typename?: 'NodesConnection';
|
||||
edges?: Array<{
|
||||
__typename?: 'NodeEdge';
|
||||
node: {
|
||||
__typename?: 'Node';
|
||||
id: string;
|
||||
rewardScore?: {
|
||||
__typename?: 'RewardScore';
|
||||
rawValidatorScore: string;
|
||||
} | null;
|
||||
rankingScore: {
|
||||
__typename?: 'RankingScore';
|
||||
performanceScore: string;
|
||||
};
|
||||
};
|
||||
} | null> | null;
|
||||
} | null;
|
||||
};
|
||||
};
|
||||
|
||||
export const PreviousEpochDocument = gql`
|
||||
query PreviousEpoch($epochId: ID) {
|
||||
epoch(id: $epochId) {
|
||||
id
|
||||
validatorsConnection {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
rewardScore {
|
||||
rawValidatorScore
|
||||
}
|
||||
rankingScore {
|
||||
performanceScore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __usePreviousEpochQuery__
|
||||
*
|
||||
* To run a query within a React component, call `usePreviousEpochQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `usePreviousEpochQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = usePreviousEpochQuery({
|
||||
* variables: {
|
||||
* epochId: // value for 'epochId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function usePreviousEpochQuery(
|
||||
baseOptions?: Apollo.QueryHookOptions<
|
||||
PreviousEpochQuery,
|
||||
PreviousEpochQueryVariables
|
||||
>
|
||||
) {
|
||||
const options = { ...defaultOptions, ...baseOptions };
|
||||
return Apollo.useQuery<PreviousEpochQuery, PreviousEpochQueryVariables>(
|
||||
PreviousEpochDocument,
|
||||
options
|
||||
);
|
||||
}
|
||||
export function usePreviousEpochLazyQuery(
|
||||
baseOptions?: Apollo.LazyQueryHookOptions<
|
||||
PreviousEpochQuery,
|
||||
PreviousEpochQueryVariables
|
||||
>
|
||||
) {
|
||||
const options = { ...defaultOptions, ...baseOptions };
|
||||
return Apollo.useLazyQuery<PreviousEpochQuery, PreviousEpochQueryVariables>(
|
||||
PreviousEpochDocument,
|
||||
options
|
||||
);
|
||||
}
|
||||
export type PreviousEpochQueryHookResult = ReturnType<
|
||||
typeof usePreviousEpochQuery
|
||||
>;
|
||||
export type PreviousEpochLazyQueryHookResult = ReturnType<
|
||||
typeof usePreviousEpochLazyQuery
|
||||
>;
|
||||
export type PreviousEpochQueryResult = Apollo.QueryResult<
|
||||
PreviousEpochQuery,
|
||||
PreviousEpochQueryVariables
|
||||
>;
|
||||
@@ -1,114 +0,0 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type LinkingsFieldsFragment = {
|
||||
__typename?: 'StakeLinking';
|
||||
id: string;
|
||||
txHash: string;
|
||||
status: Types.StakeLinkingStatus;
|
||||
};
|
||||
|
||||
export type PartyStakeLinkingsQueryVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
export type PartyStakeLinkingsQuery = {
|
||||
__typename?: 'Query';
|
||||
party?: {
|
||||
__typename?: 'Party';
|
||||
id: string;
|
||||
stakingSummary: {
|
||||
__typename?: 'StakingSummary';
|
||||
linkings: {
|
||||
__typename?: 'StakesConnection';
|
||||
edges?: Array<{
|
||||
__typename?: 'StakeLinkingEdge';
|
||||
node: {
|
||||
__typename?: 'StakeLinking';
|
||||
id: string;
|
||||
txHash: string;
|
||||
status: Types.StakeLinkingStatus;
|
||||
};
|
||||
} | null> | null;
|
||||
};
|
||||
};
|
||||
} | null;
|
||||
};
|
||||
|
||||
export const LinkingsFieldsFragmentDoc = gql`
|
||||
fragment LinkingsFields on StakeLinking {
|
||||
id
|
||||
txHash
|
||||
status
|
||||
}
|
||||
`;
|
||||
export const PartyStakeLinkingsDocument = gql`
|
||||
query PartyStakeLinkings($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
id
|
||||
stakingSummary {
|
||||
linkings {
|
||||
edges {
|
||||
node {
|
||||
...LinkingsFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${LinkingsFieldsFragmentDoc}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __usePartyStakeLinkingsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `usePartyStakeLinkingsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `usePartyStakeLinkingsQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = usePartyStakeLinkingsQuery({
|
||||
* variables: {
|
||||
* partyId: // value for 'partyId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function usePartyStakeLinkingsQuery(
|
||||
baseOptions: Apollo.QueryHookOptions<
|
||||
PartyStakeLinkingsQuery,
|
||||
PartyStakeLinkingsQueryVariables
|
||||
>
|
||||
) {
|
||||
const options = { ...defaultOptions, ...baseOptions };
|
||||
return Apollo.useQuery<
|
||||
PartyStakeLinkingsQuery,
|
||||
PartyStakeLinkingsQueryVariables
|
||||
>(PartyStakeLinkingsDocument, options);
|
||||
}
|
||||
export function usePartyStakeLinkingsLazyQuery(
|
||||
baseOptions?: Apollo.LazyQueryHookOptions<
|
||||
PartyStakeLinkingsQuery,
|
||||
PartyStakeLinkingsQueryVariables
|
||||
>
|
||||
) {
|
||||
const options = { ...defaultOptions, ...baseOptions };
|
||||
return Apollo.useLazyQuery<
|
||||
PartyStakeLinkingsQuery,
|
||||
PartyStakeLinkingsQueryVariables
|
||||
>(PartyStakeLinkingsDocument, options);
|
||||
}
|
||||
export type PartyStakeLinkingsQueryHookResult = ReturnType<
|
||||
typeof usePartyStakeLinkingsQuery
|
||||
>;
|
||||
export type PartyStakeLinkingsLazyQueryHookResult = ReturnType<
|
||||
typeof usePartyStakeLinkingsLazyQuery
|
||||
>;
|
||||
export type PartyStakeLinkingsQueryResult = Apollo.QueryResult<
|
||||
PartyStakeLinkingsQuery,
|
||||
PartyStakeLinkingsQueryVariables
|
||||
>;
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from '../../../hooks/transaction-reducer';
|
||||
import Routes from '../../routes';
|
||||
import { truncateMiddle } from '../../../lib/truncate-middle';
|
||||
import type { LinkingsFieldsFragment } from './__generated___/PartyStakeLinkings';
|
||||
import type { LinkingsFieldsFragment } from './__generated__/PartyStakeLinkings';
|
||||
|
||||
export const AssociateTransaction = ({
|
||||
amount,
|
||||
|
||||
@@ -15,8 +15,8 @@ import type {
|
||||
LinkingsFieldsFragment,
|
||||
PartyStakeLinkingsQuery,
|
||||
PartyStakeLinkingsQueryVariables,
|
||||
} from './__generated___/PartyStakeLinkings';
|
||||
import { PartyStakeLinkingsDocument } from './__generated___/PartyStakeLinkings';
|
||||
} from './__generated__/PartyStakeLinkings';
|
||||
import { PartyStakeLinkingsDocument } from './__generated__/PartyStakeLinkings';
|
||||
|
||||
export const useAddStake = (
|
||||
address: string,
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type NodesFragmentFragment = {
|
||||
__typename?: 'Node';
|
||||
avatarUrl?: string | null;
|
||||
id: string;
|
||||
name: string;
|
||||
pubkey: string;
|
||||
stakedByOperator: string;
|
||||
stakedByDelegates: string;
|
||||
stakedTotal: string;
|
||||
pendingStake: string;
|
||||
rankingScore: {
|
||||
__typename?: 'RankingScore';
|
||||
rankingScore: string;
|
||||
stakeScore: string;
|
||||
performanceScore: string;
|
||||
votingPower: string;
|
||||
status: Types.ValidatorStatus;
|
||||
};
|
||||
};
|
||||
|
||||
export type NodesQueryVariables = Types.Exact<{ [key: string]: never }>;
|
||||
|
||||
export type NodesQuery = {
|
||||
__typename?: 'Query';
|
||||
epoch: {
|
||||
__typename?: 'Epoch';
|
||||
id: string;
|
||||
timestamps: {
|
||||
__typename?: 'EpochTimestamps';
|
||||
start?: any | null;
|
||||
end?: any | null;
|
||||
expiry?: any | null;
|
||||
};
|
||||
};
|
||||
nodesConnection: {
|
||||
__typename?: 'NodesConnection';
|
||||
edges?: Array<{
|
||||
__typename?: 'NodeEdge';
|
||||
node: {
|
||||
__typename?: 'Node';
|
||||
avatarUrl?: string | null;
|
||||
id: string;
|
||||
name: string;
|
||||
pubkey: string;
|
||||
stakedByOperator: string;
|
||||
stakedByDelegates: string;
|
||||
stakedTotal: string;
|
||||
pendingStake: string;
|
||||
rankingScore: {
|
||||
__typename?: 'RankingScore';
|
||||
rankingScore: string;
|
||||
stakeScore: string;
|
||||
performanceScore: string;
|
||||
votingPower: string;
|
||||
status: Types.ValidatorStatus;
|
||||
};
|
||||
};
|
||||
} | null> | null;
|
||||
};
|
||||
nodeData?: { __typename?: 'NodeData'; stakedTotal: string } | null;
|
||||
};
|
||||
|
||||
export const NodesFragmentFragmentDoc = gql`
|
||||
fragment NodesFragment on Node {
|
||||
avatarUrl
|
||||
id
|
||||
name
|
||||
pubkey
|
||||
stakedByOperator
|
||||
stakedByDelegates
|
||||
stakedTotal
|
||||
pendingStake
|
||||
rankingScore {
|
||||
rankingScore
|
||||
stakeScore
|
||||
performanceScore
|
||||
votingPower
|
||||
status
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const NodesDocument = gql`
|
||||
query Nodes {
|
||||
epoch {
|
||||
id
|
||||
timestamps {
|
||||
start
|
||||
end
|
||||
expiry
|
||||
}
|
||||
}
|
||||
nodesConnection {
|
||||
edges {
|
||||
node {
|
||||
...NodesFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
nodeData {
|
||||
stakedTotal
|
||||
}
|
||||
}
|
||||
${NodesFragmentFragmentDoc}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useNodesQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useNodesQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useNodesQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useNodesQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useNodesQuery(
|
||||
baseOptions?: Apollo.QueryHookOptions<NodesQuery, NodesQueryVariables>
|
||||
) {
|
||||
const options = { ...defaultOptions, ...baseOptions };
|
||||
return Apollo.useQuery<NodesQuery, NodesQueryVariables>(
|
||||
NodesDocument,
|
||||
options
|
||||
);
|
||||
}
|
||||
export function useNodesLazyQuery(
|
||||
baseOptions?: Apollo.LazyQueryHookOptions<NodesQuery, NodesQueryVariables>
|
||||
) {
|
||||
const options = { ...defaultOptions, ...baseOptions };
|
||||
return Apollo.useLazyQuery<NodesQuery, NodesQueryVariables>(
|
||||
NodesDocument,
|
||||
options
|
||||
);
|
||||
}
|
||||
export type NodesQueryHookResult = ReturnType<typeof useNodesQuery>;
|
||||
export type NodesLazyQueryHookResult = ReturnType<typeof useNodesLazyQuery>;
|
||||
export type NodesQueryResult = Apollo.QueryResult<
|
||||
NodesQuery,
|
||||
NodesQueryVariables
|
||||
>;
|
||||
@@ -1,36 +1,53 @@
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { EpochCountdown } from '../../../components/epoch-countdown';
|
||||
import { useNodesQuery } from './__generated___/Nodes';
|
||||
import { usePreviousEpochQuery } from '../__generated___/PreviousEpoch';
|
||||
import { useNodesQuery } from './__generated__/Nodes';
|
||||
import { useStakingQuery } from '../__generated__/Staking';
|
||||
import { usePreviousEpochQuery } from '../__generated__/PreviousEpoch';
|
||||
import { ValidatorTables } from './validator-tables';
|
||||
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
|
||||
export const EpochData = () => {
|
||||
// errorPolicy due to vegaprotocol/vega issue 5898
|
||||
const { data, error, loading, refetch } = useNodesQuery();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const {
|
||||
data: nodesData,
|
||||
error: nodesError,
|
||||
loading: nodesLoading,
|
||||
refetch,
|
||||
} = useNodesQuery();
|
||||
const { data: userStakingData } = useStakingQuery({
|
||||
variables: {
|
||||
partyId: pubKey || '',
|
||||
},
|
||||
});
|
||||
const { data: previousEpochData } = usePreviousEpochQuery({
|
||||
variables: {
|
||||
epochId: (Number(data?.epoch.id) - 1).toString(),
|
||||
epochId: (Number(nodesData?.epoch.id) - 1).toString(),
|
||||
},
|
||||
skip: !data?.epoch.id,
|
||||
skip: !nodesData?.epoch.id,
|
||||
});
|
||||
|
||||
useRefreshAfterEpoch(data?.epoch.timestamps.expiry, refetch);
|
||||
useRefreshAfterEpoch(nodesData?.epoch.timestamps.expiry, refetch);
|
||||
|
||||
return (
|
||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||
{data?.epoch &&
|
||||
data.epoch.timestamps.start &&
|
||||
data?.epoch.timestamps.expiry && (
|
||||
<AsyncRenderer loading={nodesLoading} error={nodesError} data={nodesData}>
|
||||
{nodesData?.epoch &&
|
||||
nodesData.epoch.timestamps.start &&
|
||||
nodesData?.epoch.timestamps.expiry && (
|
||||
<div className="mb-10">
|
||||
<EpochCountdown
|
||||
id={data.epoch.id}
|
||||
startDate={new Date(data.epoch.timestamps.start)}
|
||||
endDate={new Date(data.epoch.timestamps.expiry)}
|
||||
id={nodesData.epoch.id}
|
||||
startDate={new Date(nodesData.epoch.timestamps.start)}
|
||||
endDate={new Date(nodesData.epoch.timestamps.expiry)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<ValidatorTables data={data} previousEpochData={previousEpochData} />
|
||||
<ValidatorTables
|
||||
nodesData={nodesData}
|
||||
userStakingData={userStakingData}
|
||||
previousEpochData={previousEpochData}
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
);
|
||||
};
|
||||
|
||||
+14
-8
@@ -3,14 +3,15 @@ import { act, fireEvent, render, screen } from '@testing-library/react';
|
||||
import { ConsensusValidatorsTable } from './consensus-validators-table';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { NodesDocument } from '../__generated___/Nodes';
|
||||
import { PreviousEpochDocument } from '../../__generated___/PreviousEpoch';
|
||||
import { NodesDocument } from '../__generated__/Nodes';
|
||||
import { PreviousEpochDocument } from '../../__generated__/PreviousEpoch';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import type { NodesFragmentFragment } from '../__generated___/Nodes';
|
||||
import type { PreviousEpochQuery } from '../../__generated___/PreviousEpoch';
|
||||
import type { NodesFragmentFragment } from '../__generated__/Nodes';
|
||||
import type { PreviousEpochQuery } from '../../__generated__/PreviousEpoch';
|
||||
import type { ValidatorsView } from './validator-tables';
|
||||
|
||||
const nodeFactory = (
|
||||
overrides?: PartialDeep<NodesFragmentFragment>
|
||||
@@ -80,9 +81,10 @@ const MOCK_PREVIOUS_EPOCH: PreviousEpochQuery = {
|
||||
id: 'ccc022b7e63a4d0a6d3a193c3940c88574060e58a184964c994998d86835a1b4',
|
||||
rewardScore: {
|
||||
rawValidatorScore: '0.25',
|
||||
performanceScore: '0.9998677767864936',
|
||||
},
|
||||
rankingScore: {
|
||||
performanceScore: '0.9998677767864936',
|
||||
stakeScore: '0.2499583402766206',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -91,9 +93,10 @@ const MOCK_PREVIOUS_EPOCH: PreviousEpochQuery = {
|
||||
id: '966438c6bffac737cfb08173ffcb3f393c4692b099ad80cb45a82e2dc0a8cf99',
|
||||
rewardScore: {
|
||||
rawValidatorScore: '0.3',
|
||||
performanceScore: '1',
|
||||
},
|
||||
rankingScore: {
|
||||
performanceScore: '1',
|
||||
stakeScore: '0.25',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -102,9 +105,10 @@ const MOCK_PREVIOUS_EPOCH: PreviousEpochQuery = {
|
||||
id: '12c81b738e8051152e1afe44376ec37bca9216466e6d44cdd772194bad0ada81',
|
||||
rewardScore: {
|
||||
rawValidatorScore: '0.35',
|
||||
performanceScore: '0.999629748500531',
|
||||
},
|
||||
rankingScore: {
|
||||
performanceScore: '0.999629748500531',
|
||||
stakeScore: '0.2312',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -142,7 +146,8 @@ const MOCK_TOTAL_STAKE = '28832590188747439203824';
|
||||
|
||||
const renderValidatorsTable = (
|
||||
data = MOCK_NODES,
|
||||
previousEpochData = MOCK_PREVIOUS_EPOCH
|
||||
previousEpochData = MOCK_PREVIOUS_EPOCH,
|
||||
validatorsView: ValidatorsView = 'all'
|
||||
) => {
|
||||
return render(
|
||||
<AppStateProvider initialState={{ decimals: 18 }}>
|
||||
@@ -152,6 +157,7 @@ const renderValidatorsTable = (
|
||||
data={data}
|
||||
previousEpochData={previousEpochData}
|
||||
totalStake={MOCK_TOTAL_STAKE}
|
||||
validatorsView={validatorsView}
|
||||
/>
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
|
||||
+68
-40
@@ -10,7 +10,6 @@ import {
|
||||
getFormattedPerformanceScore,
|
||||
getLastEpochScoreAndPerformance,
|
||||
getNormalisedVotingPower,
|
||||
getOverstakedAmount,
|
||||
getOverstakingPenalty,
|
||||
getPerformancePenalty,
|
||||
getTotalPenalties,
|
||||
@@ -19,7 +18,9 @@ import {
|
||||
import {
|
||||
defaultColDef,
|
||||
NODE_LIST_GRID_STYLES,
|
||||
PendingStakeRenderer,
|
||||
stakedTotalPercentage,
|
||||
StakeShareRenderer,
|
||||
TotalPenaltiesRenderer,
|
||||
TotalStakeRenderer,
|
||||
ValidatorFields,
|
||||
@@ -50,10 +51,12 @@ interface CanonisedConsensusNodeProps {
|
||||
[ValidatorFields.STAKED_BY_OPERATOR]: string;
|
||||
[ValidatorFields.PERFORMANCE_SCORE]: string;
|
||||
[ValidatorFields.PERFORMANCE_PENALTY]: string;
|
||||
[ValidatorFields.OVERSTAKED_AMOUNT]: string;
|
||||
[ValidatorFields.OVERSTAKING_PENALTY]: string;
|
||||
[ValidatorFields.TOTAL_PENALTIES]: string;
|
||||
[ValidatorFields.PENDING_STAKE]: string;
|
||||
[ValidatorFields.STAKED_BY_USER]: string | undefined;
|
||||
[ValidatorFields.PENDING_USER_STAKE]: string | undefined;
|
||||
[ValidatorFields.USER_STAKE_SHARE]: string | undefined;
|
||||
}
|
||||
|
||||
const getRowHeight = (params: RowHeightParams) => {
|
||||
@@ -61,7 +64,7 @@ const getRowHeight = (params: RowHeightParams) => {
|
||||
// Note: this value will change if the height of the top third cell renderer changes
|
||||
return 138;
|
||||
}
|
||||
return 52;
|
||||
return 68;
|
||||
};
|
||||
|
||||
const TopThirdCellRenderer = (
|
||||
@@ -117,6 +120,7 @@ export const ConsensusValidatorsTable = ({
|
||||
data,
|
||||
previousEpochData,
|
||||
totalStake,
|
||||
validatorsView,
|
||||
}: ValidatorsTableProps) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
@@ -129,7 +133,7 @@ export const ConsensusValidatorsTable = ({
|
||||
|
||||
const nodes = useMemo(() => {
|
||||
if (!data || !previousEpochData) return [];
|
||||
const canonisedNodes = data
|
||||
let canonisedNodes = data
|
||||
.sort((a, b) => {
|
||||
const aVotingPower = new BigNumber(a.rankingScore.votingPower);
|
||||
const bVotingPower = new BigNumber(b.rankingScore.votingPower);
|
||||
@@ -154,15 +158,15 @@ export const ConsensusValidatorsTable = ({
|
||||
rankingScore: { stakeScore, votingPower },
|
||||
pendingStake,
|
||||
votingPowerRanking,
|
||||
stakedByUser,
|
||||
pendingUserStake,
|
||||
userStakeShare,
|
||||
}) => {
|
||||
const { rawValidatorScore, performanceScore } =
|
||||
getLastEpochScoreAndPerformance(previousEpochData, id);
|
||||
|
||||
const overstakedAmount = getOverstakedAmount(
|
||||
rawValidatorScore,
|
||||
stakedTotal,
|
||||
totalStake
|
||||
);
|
||||
const {
|
||||
rawValidatorScore: previousEpochValidatorScore,
|
||||
performanceScore: previousEpochPerformanceScore,
|
||||
stakeScore: previousEpochStakeScore,
|
||||
} = getLastEpochScoreAndPerformance(previousEpochData, id);
|
||||
|
||||
return {
|
||||
id,
|
||||
@@ -175,7 +179,7 @@ export const ConsensusValidatorsTable = ({
|
||||
[ValidatorFields.NORMALISED_VOTING_POWER]:
|
||||
getNormalisedVotingPower(votingPower),
|
||||
[ValidatorFields.UNNORMALISED_VOTING_POWER]:
|
||||
getUnnormalisedVotingPower(rawValidatorScore),
|
||||
getUnnormalisedVotingPower(previousEpochValidatorScore),
|
||||
[ValidatorFields.STAKE_SHARE]: stakedTotalPercentage(stakeScore),
|
||||
[ValidatorFields.STAKED_BY_DELEGATES]: formatNumber(
|
||||
toBigNum(stakedByDelegates, decimals),
|
||||
@@ -185,28 +189,45 @@ export const ConsensusValidatorsTable = ({
|
||||
toBigNum(stakedByOperator, decimals),
|
||||
2
|
||||
),
|
||||
[ValidatorFields.PERFORMANCE_SCORE]:
|
||||
getFormattedPerformanceScore(performanceScore).toString(),
|
||||
[ValidatorFields.PERFORMANCE_PENALTY]:
|
||||
getPerformancePenalty(performanceScore),
|
||||
[ValidatorFields.OVERSTAKED_AMOUNT]: overstakedAmount.toString(),
|
||||
[ValidatorFields.PERFORMANCE_SCORE]: getFormattedPerformanceScore(
|
||||
previousEpochPerformanceScore
|
||||
).toString(),
|
||||
[ValidatorFields.PERFORMANCE_PENALTY]: getPerformancePenalty(
|
||||
previousEpochPerformanceScore
|
||||
),
|
||||
[ValidatorFields.OVERSTAKING_PENALTY]: getOverstakingPenalty(
|
||||
overstakedAmount,
|
||||
totalStake
|
||||
previousEpochValidatorScore,
|
||||
previousEpochStakeScore
|
||||
),
|
||||
[ValidatorFields.TOTAL_PENALTIES]: getTotalPenalties(
|
||||
rawValidatorScore,
|
||||
performanceScore,
|
||||
previousEpochValidatorScore,
|
||||
previousEpochPerformanceScore,
|
||||
stakedTotal,
|
||||
totalStake
|
||||
),
|
||||
[ValidatorFields.PENDING_STAKE]: pendingStake,
|
||||
decimals,
|
||||
[ValidatorFields.STAKED_BY_USER]: stakedByUser
|
||||
? formatNumber(toBigNum(stakedByUser, decimals), 2)
|
||||
: undefined,
|
||||
[ValidatorFields.PENDING_USER_STAKE]: pendingUserStake,
|
||||
[ValidatorFields.USER_STAKE_SHARE]: userStakeShare
|
||||
? stakedTotalPercentage(userStakeShare)
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
if (canonisedNodes.length < 3 || !hideTopThird) {
|
||||
if (validatorsView === 'myStake') {
|
||||
canonisedNodes = canonisedNodes.filter(
|
||||
(node) => node[ValidatorFields.STAKED_BY_USER] !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
canonisedNodes.length < 3 ||
|
||||
!hideTopThird ||
|
||||
validatorsView === 'myStake'
|
||||
) {
|
||||
return canonisedNodes;
|
||||
}
|
||||
|
||||
@@ -291,7 +312,14 @@ export const ConsensusValidatorsTable = ({
|
||||
},
|
||||
...remaining,
|
||||
];
|
||||
}, [data, decimals, hideTopThird, previousEpochData, totalStake]);
|
||||
}, [
|
||||
data,
|
||||
decimals,
|
||||
hideTopThird,
|
||||
previousEpochData,
|
||||
totalStake,
|
||||
validatorsView,
|
||||
]);
|
||||
|
||||
const ConsensusTable = forwardRef<AgGridReact>((_, gridRef) => {
|
||||
const colDefs = useMemo<ColDef[]>(
|
||||
@@ -311,7 +339,7 @@ export const ConsensusValidatorsTable = ({
|
||||
return a > b ? 1 : -1;
|
||||
},
|
||||
pinned: 'left',
|
||||
width: 240,
|
||||
width: 260,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.STAKE,
|
||||
@@ -320,6 +348,20 @@ export const ConsensusValidatorsTable = ({
|
||||
cellRenderer: TotalStakeRenderer,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.PENDING_STAKE,
|
||||
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
|
||||
headerTooltip: t('PendingStakeDescription').toString(),
|
||||
cellRenderer: PendingStakeRenderer,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.STAKE_SHARE,
|
||||
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
|
||||
headerTooltip: t('StakeShareDescription').toString(),
|
||||
cellRenderer: StakeShareRenderer,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.NORMALISED_VOTING_POWER,
|
||||
headerName: t(ValidatorFields.NORMALISED_VOTING_POWER).toString(),
|
||||
@@ -328,12 +370,6 @@ export const ConsensusValidatorsTable = ({
|
||||
width: 200,
|
||||
sort: 'desc',
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.STAKE_SHARE,
|
||||
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
|
||||
headerTooltip: t('StakeShareDescription').toString(),
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.TOTAL_PENALTIES,
|
||||
headerName: t(ValidatorFields.TOTAL_PENALTIES).toString(),
|
||||
@@ -341,14 +377,6 @@ export const ConsensusValidatorsTable = ({
|
||||
cellRenderer: TotalPenaltiesRenderer,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.PENDING_STAKE,
|
||||
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
|
||||
headerTooltip: t('PendingStakeDescription').toString(),
|
||||
valueFormatter: ({ value }) =>
|
||||
formatNumber(toBigNum(value, decimals), 2),
|
||||
width: 110,
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
import {
|
||||
getLastEpochScoreAndPerformance,
|
||||
getTotalPenalties,
|
||||
} from '../../shared';
|
||||
import { stakedTotalPercentage } from './shared';
|
||||
|
||||
const MOCK_PREVIOUS_EPOCH = {
|
||||
epoch: {
|
||||
id: '1',
|
||||
validatorsConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: '0x123',
|
||||
rewardScore: {
|
||||
rawValidatorScore: '0.25',
|
||||
},
|
||||
rankingScore: {
|
||||
performanceScore: '0.75',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('stakedTotalPercentage', () => {
|
||||
it('should return the correct percentage as a string, 2dp', () => {
|
||||
expect(stakedTotalPercentage('1.2345')).toBe('123.45%');
|
||||
});
|
||||
});
|
||||
|
||||
describe('totalPenalties', () => {
|
||||
it('should return the correct penalty based on arbitrary values, test 1', () => {
|
||||
expect(
|
||||
getTotalPenalties(
|
||||
getLastEpochScoreAndPerformance(MOCK_PREVIOUS_EPOCH, '0x123')
|
||||
.rawValidatorScore,
|
||||
'0.1',
|
||||
'5000',
|
||||
'100000'
|
||||
)
|
||||
).toBe('50.00%');
|
||||
});
|
||||
|
||||
it('should return the correct penalty based on lower performance score than first test', () => {
|
||||
expect(
|
||||
getTotalPenalties(
|
||||
getLastEpochScoreAndPerformance(MOCK_PREVIOUS_EPOCH, '0x123')
|
||||
.rawValidatorScore,
|
||||
'0.05',
|
||||
'5000',
|
||||
'100000'
|
||||
)
|
||||
).toBe('75.00%');
|
||||
});
|
||||
|
||||
it('should return the correct penalty based on higher amount of stake than other tests (great penalty due to anti-whaling)', () => {
|
||||
expect(
|
||||
getTotalPenalties(
|
||||
getLastEpochScoreAndPerformance(MOCK_PREVIOUS_EPOCH, '0x123')
|
||||
.rawValidatorScore,
|
||||
'0.1',
|
||||
'5000',
|
||||
'5500'
|
||||
)
|
||||
).toBe('97.25%');
|
||||
});
|
||||
});
|
||||
@@ -10,9 +10,12 @@ import {
|
||||
Tooltip,
|
||||
TooltipCellComponent,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { NodesFragmentFragment } from '../__generated___/Nodes';
|
||||
import type { PreviousEpochQuery } from '../../__generated___/PreviousEpoch';
|
||||
import { BigNumber } from '../../../../lib/bignumber';
|
||||
import type { NodesFragmentFragment } from '../__generated__/Nodes';
|
||||
import type { PreviousEpochQuery } from '../../__generated__/PreviousEpoch';
|
||||
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
||||
import type { StakingDelegationFieldsFragment } from '../../__generated__/Staking';
|
||||
import type { ValidatorsView } from './validator-tables';
|
||||
|
||||
export enum ValidatorFields {
|
||||
RANKING_INDEX = 'rankingIndex',
|
||||
@@ -31,12 +34,49 @@ export enum ValidatorFields {
|
||||
PERFORMANCE_PENALTY = 'performancePenalty',
|
||||
OVERSTAKED_AMOUNT = 'overstakedAmount',
|
||||
OVERSTAKING_PENALTY = 'overstakingPenalty',
|
||||
// the following are additional fields added to the validator object displaying user data
|
||||
STAKED_BY_USER = 'stakedByUser',
|
||||
PENDING_USER_STAKE = 'pendingUserStake',
|
||||
USER_STAKE_SHARE = 'userStakeShare',
|
||||
}
|
||||
|
||||
export const addUserDataToValidator = (
|
||||
validator: NodesFragmentFragment,
|
||||
currentEpochUserStaking: StakingDelegationFieldsFragment | undefined,
|
||||
nextEpochUserStaking: StakingDelegationFieldsFragment | undefined,
|
||||
currentUserStakeAvailable: string
|
||||
) => {
|
||||
return {
|
||||
...validator,
|
||||
[ValidatorFields.STAKED_BY_USER]:
|
||||
currentEpochUserStaking && Number(currentEpochUserStaking?.amount) > 0
|
||||
? currentEpochUserStaking.amount
|
||||
: undefined,
|
||||
[ValidatorFields.PENDING_USER_STAKE]: nextEpochUserStaking
|
||||
? new BigNumber(nextEpochUserStaking?.amount)
|
||||
.minus(new BigNumber(currentEpochUserStaking?.amount || 0))
|
||||
.toString()
|
||||
: undefined,
|
||||
[ValidatorFields.USER_STAKE_SHARE]:
|
||||
currentEpochUserStaking && Number(currentEpochUserStaking.amount) > 0
|
||||
? new BigNumber(currentEpochUserStaking.amount).dividedBy(
|
||||
new BigNumber(currentUserStakeAvailable)
|
||||
)
|
||||
: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
export type ValidatorWithUserData = NodesFragmentFragment & {
|
||||
stakedByUser?: string;
|
||||
pendingUserStake?: string;
|
||||
userStakeShare?: string;
|
||||
};
|
||||
|
||||
export interface ValidatorsTableProps {
|
||||
data: NodesFragmentFragment[] | undefined;
|
||||
data: ValidatorWithUserData[] | undefined;
|
||||
previousEpochData: PreviousEpochQuery | undefined;
|
||||
totalStake: string;
|
||||
validatorsView: ValidatorsView;
|
||||
}
|
||||
|
||||
// Custom styling to account for the scrollbar. This is needed because the
|
||||
@@ -58,19 +98,23 @@ export const defaultColDef = {
|
||||
resizable: true,
|
||||
autoHeight: true,
|
||||
comparator: (a: string, b: string) => parseFloat(a) - parseFloat(b),
|
||||
cellStyle: { margin: '10px 0', padding: '0 12px' },
|
||||
tooltipComponent: TooltipCellComponent,
|
||||
cellStyle: { display: 'flex', alignItems: 'center', padding: '0 10px' },
|
||||
};
|
||||
|
||||
interface ValidatorRendererProps {
|
||||
data: { id: string; validator: { avatarUrl: string; name: string } };
|
||||
data: {
|
||||
id: string;
|
||||
validator: { avatarUrl: string; name: string };
|
||||
stakedByUser: string | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
export const ValidatorRenderer = ({ data }: ValidatorRendererProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { avatarUrl, name } = data.validator;
|
||||
return (
|
||||
<div className="grid grid-cols-[1fr_auto] gap-2 items-center">
|
||||
<div className="w-[238px] grid grid-cols-[1fr_auto] gap-2 items-center">
|
||||
<span className="flex overflow-hidden">
|
||||
{avatarUrl && (
|
||||
<img
|
||||
@@ -83,9 +127,19 @@ export const ValidatorRenderer = ({ data }: ValidatorRendererProps) => {
|
||||
<span>{name}</span>
|
||||
</span>
|
||||
<Link to={data.id}>
|
||||
<Button size="sm" fill={true}>
|
||||
{t('Stake')}
|
||||
</Button>
|
||||
{data.stakedByUser ? (
|
||||
<Button
|
||||
data-testid="my-stake-btn"
|
||||
size="sm"
|
||||
className="text-vega-green border-vega-green"
|
||||
>
|
||||
{t('myStake')}
|
||||
</Button>
|
||||
) : (
|
||||
<Button data-testid="stake-btn" size="sm" fill={true}>
|
||||
{t('Stake')}
|
||||
</Button>
|
||||
)}
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
@@ -102,8 +156,14 @@ export const StakeNeededForPromotionRenderer = ({
|
||||
data,
|
||||
}: StakeNeededForPromotionRendererProps) => {
|
||||
return (
|
||||
<Tooltip description={data.stakeNeededForPromotionDescription}>
|
||||
<span>
|
||||
<Tooltip
|
||||
description={
|
||||
<span data-testid="stake-needed-for-promotion-tooltip">
|
||||
{data.stakeNeededForPromotionDescription}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<span data-testid="stake-needed-for-promotion">
|
||||
{data.stakeNeededForPromotion &&
|
||||
formatNumber(data.stakeNeededForPromotion, 2)}
|
||||
</span>
|
||||
@@ -134,7 +194,59 @@ export const VotingPowerRenderer = ({ data }: VotingPowerRendererProps) => {
|
||||
</>
|
||||
}
|
||||
>
|
||||
<span>{data.normalisedVotingPower}</span>
|
||||
<span data-testid="normalised-voting-power">
|
||||
{data.normalisedVotingPower}
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
interface PendingStakeRendererProps {
|
||||
data: {
|
||||
pendingStake: string;
|
||||
pendingUserStake: string | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
export const PendingStakeRenderer = ({ data }: PendingStakeRendererProps) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
appState: { decimals },
|
||||
} = useAppState();
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
description={
|
||||
<>
|
||||
<div data-testid="pending-stake-tooltip">
|
||||
{t('pendingStake')}:{' '}
|
||||
{formatNumber(toBigNum(data.pendingStake, decimals), decimals)}
|
||||
</div>
|
||||
{data.pendingUserStake && (
|
||||
<div
|
||||
className="text-vega-green border-t border-t-vega-dark-200 mt-1.5 pt-1"
|
||||
data-testid="pending-user-stake-tooltip"
|
||||
>
|
||||
{t('myPendingStake')}:{' '}
|
||||
{formatNumber(
|
||||
toBigNum(data.pendingUserStake, decimals),
|
||||
decimals
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
{data.pendingUserStake && data.pendingStake !== '0' && (
|
||||
<span data-testid="pending-user-stake" className="text-vega-green">
|
||||
{formatNumber(toBigNum(data.pendingUserStake, decimals), 2)}
|
||||
</span>
|
||||
)}
|
||||
<span data-testid="total-pending-stake">
|
||||
{formatNumber(toBigNum(data.pendingStake, decimals), 2)}
|
||||
</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
@@ -144,6 +256,7 @@ interface TotalStakeRendererProps {
|
||||
stake: string;
|
||||
stakedByDelegates: string;
|
||||
stakedByOperator: string;
|
||||
stakedByUser: string | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -165,18 +278,52 @@ export const TotalStakeRenderer = ({ data }: TotalStakeRendererProps) => {
|
||||
<div data-testid="staked-delegates-tooltip">
|
||||
{t('stakedByDelegates')}: {data.stakedByDelegates.toString()}
|
||||
</div>
|
||||
<div data-testid="total-staked-tooltip">
|
||||
{t('totalStake')}:{' '}
|
||||
<span className="font-bold">{formattedStake}</span>
|
||||
<div className="font-bold" data-testid="total-staked-tooltip">
|
||||
{t('totalStake')}: {formattedStake}
|
||||
</div>
|
||||
{data.stakedByUser && (
|
||||
<div
|
||||
className="text-vega-green border-t border-t-vega-dark-200 mt-1.5 pt-1"
|
||||
data-testid="staked-by-user-tooltip"
|
||||
>
|
||||
{t('stakedByMe')}: {data.stakedByUser}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<span>{formattedStake}</span>
|
||||
<div className="flex flex-col">
|
||||
{data.stakedByUser && (
|
||||
<span data-testid="user-stake" className="text-vega-green">
|
||||
{data.stakedByUser}
|
||||
</span>
|
||||
)}
|
||||
<span data-testid="total-stake">{formattedStake}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
interface StakeShareRendererProps {
|
||||
data: {
|
||||
stakeShare: string;
|
||||
userStakeShare: string | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
export const StakeShareRenderer = ({ data }: StakeShareRendererProps) => {
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
{data.userStakeShare && (
|
||||
<span data-testid="user-stake-share" className="text-vega-green">
|
||||
{data.userStakeShare}
|
||||
</span>
|
||||
)}
|
||||
<span data-testid="total-stake-share">{data.stakeShare}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface TotalPenaltiesRendererProps {
|
||||
data: {
|
||||
performanceScore: string;
|
||||
@@ -209,7 +356,7 @@ export const TotalPenaltiesRenderer = ({
|
||||
</>
|
||||
}
|
||||
>
|
||||
<span>{data.totalPenalties}</span>
|
||||
<span data-testid="total-penalty">{data.totalPenalties}</span>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
+55
-36
@@ -7,7 +7,6 @@ import { BigNumber } from '../../../../lib/bignumber';
|
||||
import {
|
||||
getFormattedPerformanceScore,
|
||||
getLastEpochScoreAndPerformance,
|
||||
getOverstakedAmount,
|
||||
getOverstakingPenalty,
|
||||
getPerformancePenalty,
|
||||
getTotalPenalties,
|
||||
@@ -21,6 +20,8 @@ import {
|
||||
ValidatorRenderer,
|
||||
TotalPenaltiesRenderer,
|
||||
TotalStakeRenderer,
|
||||
StakeShareRenderer,
|
||||
PendingStakeRenderer,
|
||||
} from './shared';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { ColDef } from 'ag-grid-community';
|
||||
@@ -38,6 +39,7 @@ export const StandbyPendingValidatorsTable = ({
|
||||
totalStake,
|
||||
stakeNeededForPromotion,
|
||||
stakeNeededForPromotionDescription,
|
||||
validatorsView,
|
||||
}: StandbyPendingValidatorsTableProps) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
@@ -47,7 +49,7 @@ export const StandbyPendingValidatorsTable = ({
|
||||
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
|
||||
const nodes = useMemo(() => {
|
||||
let nodes = useMemo(() => {
|
||||
if (!data) return [];
|
||||
|
||||
return data
|
||||
@@ -75,22 +77,25 @@ export const StandbyPendingValidatorsTable = ({
|
||||
rankingScore: { stakeScore },
|
||||
pendingStake,
|
||||
votingPowerRanking,
|
||||
stakedByUser,
|
||||
pendingUserStake,
|
||||
userStakeShare,
|
||||
}) => {
|
||||
const { rawValidatorScore, performanceScore } =
|
||||
getLastEpochScoreAndPerformance(previousEpochData, id);
|
||||
const {
|
||||
rawValidatorScore: previousEpochValidatorScore,
|
||||
performanceScore: previousEpochPerformanceScore,
|
||||
stakeScore: previousEpochStakeScore,
|
||||
} = getLastEpochScoreAndPerformance(previousEpochData, id);
|
||||
|
||||
const overstakedAmount = getOverstakedAmount(
|
||||
rawValidatorScore,
|
||||
stakedTotal,
|
||||
totalStake
|
||||
);
|
||||
let individualStakeNeededForPromotion,
|
||||
individualStakeNeededForPromotionDescription;
|
||||
|
||||
if (stakeNeededForPromotion && performanceScore) {
|
||||
if (stakeNeededForPromotion && previousEpochPerformanceScore) {
|
||||
const stakedTotalBigNum = new BigNumber(stakedTotal);
|
||||
const stakeNeededBigNum = new BigNumber(stakeNeededForPromotion);
|
||||
const performanceScoreBigNum = new BigNumber(performanceScore);
|
||||
const performanceScoreBigNum = new BigNumber(
|
||||
previousEpochPerformanceScore
|
||||
);
|
||||
|
||||
const calc = stakeNeededBigNum
|
||||
.dividedBy(performanceScoreBigNum)
|
||||
@@ -136,22 +141,30 @@ export const StandbyPendingValidatorsTable = ({
|
||||
toBigNum(stakedByOperator, decimals),
|
||||
2
|
||||
),
|
||||
[ValidatorFields.PERFORMANCE_SCORE]:
|
||||
getFormattedPerformanceScore(performanceScore).toString(),
|
||||
[ValidatorFields.PERFORMANCE_PENALTY]:
|
||||
getPerformancePenalty(performanceScore),
|
||||
[ValidatorFields.OVERSTAKED_AMOUNT]: overstakedAmount.toString(),
|
||||
[ValidatorFields.PERFORMANCE_SCORE]: getFormattedPerformanceScore(
|
||||
previousEpochPerformanceScore
|
||||
).toString(),
|
||||
[ValidatorFields.PERFORMANCE_PENALTY]: getPerformancePenalty(
|
||||
previousEpochPerformanceScore
|
||||
),
|
||||
[ValidatorFields.OVERSTAKING_PENALTY]: getOverstakingPenalty(
|
||||
overstakedAmount,
|
||||
totalStake
|
||||
previousEpochValidatorScore,
|
||||
previousEpochStakeScore
|
||||
),
|
||||
[ValidatorFields.TOTAL_PENALTIES]: getTotalPenalties(
|
||||
rawValidatorScore,
|
||||
performanceScore,
|
||||
previousEpochValidatorScore,
|
||||
previousEpochPerformanceScore,
|
||||
stakedTotal,
|
||||
totalStake
|
||||
),
|
||||
[ValidatorFields.PENDING_STAKE]: pendingStake,
|
||||
[ValidatorFields.STAKED_BY_USER]: stakedByUser
|
||||
? formatNumber(toBigNum(stakedByUser, decimals), 2)
|
||||
: undefined,
|
||||
[ValidatorFields.PENDING_USER_STAKE]: pendingUserStake,
|
||||
[ValidatorFields.USER_STAKE_SHARE]: userStakeShare
|
||||
? stakedTotalPercentage(userStakeShare)
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -165,6 +178,12 @@ export const StandbyPendingValidatorsTable = ({
|
||||
totalStake,
|
||||
]);
|
||||
|
||||
if (validatorsView === 'myStake') {
|
||||
nodes = nodes.filter(
|
||||
(node) => node[ValidatorFields.STAKED_BY_USER] !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
const StandbyPendingTable = forwardRef<AgGridReact>((_, gridRef) => {
|
||||
const colDefs = useMemo<ColDef[]>(
|
||||
() => [
|
||||
@@ -180,7 +199,7 @@ export const StandbyPendingValidatorsTable = ({
|
||||
cellRenderer: ValidatorRenderer,
|
||||
comparator: ({ name: a }, { name: b }) => Math.sign(a - b),
|
||||
pinned: 'left',
|
||||
width: 240,
|
||||
width: 260,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.STAKE,
|
||||
@@ -189,6 +208,20 @@ export const StandbyPendingValidatorsTable = ({
|
||||
cellRenderer: TotalStakeRenderer,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.PENDING_STAKE,
|
||||
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
|
||||
headerTooltip: t('PendingStakeDescription').toString(),
|
||||
cellRenderer: PendingStakeRenderer,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.STAKE_SHARE,
|
||||
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
|
||||
headerTooltip: t('StakeShareDescription').toString(),
|
||||
cellRenderer: StakeShareRenderer,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.STAKE_NEEDED_FOR_PROMOTION,
|
||||
headerName: t(ValidatorFields.STAKE_NEEDED_FOR_PROMOTION).toString(),
|
||||
@@ -199,12 +232,6 @@ export const StandbyPendingValidatorsTable = ({
|
||||
width: 210,
|
||||
sort: 'asc',
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.STAKE_SHARE,
|
||||
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
|
||||
headerTooltip: t('StakeShareDescription').toString(),
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.TOTAL_PENALTIES,
|
||||
headerName: t(ValidatorFields.TOTAL_PENALTIES).toString(),
|
||||
@@ -212,14 +239,6 @@ export const StandbyPendingValidatorsTable = ({
|
||||
cellRenderer: TotalPenaltiesRenderer,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: ValidatorFields.PENDING_STAKE,
|
||||
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
|
||||
headerTooltip: t('PendingStakeDescription').toString(),
|
||||
valueFormatter: ({ value }) =>
|
||||
formatNumber(toBigNum(value, decimals), 2),
|
||||
width: 110,
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
@@ -230,7 +249,7 @@ export const StandbyPendingValidatorsTable = ({
|
||||
domLayout="autoHeight"
|
||||
style={{ width: '100%' }}
|
||||
customThemeParams={NODE_LIST_GRID_STYLES}
|
||||
rowHeight={52}
|
||||
rowHeight={68}
|
||||
defaultColDef={defaultColDef}
|
||||
tooltipShowDelay={0}
|
||||
animateRows={true}
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { ConsensusValidatorsTable } from './consensus-validators-table';
|
||||
import { StandbyPendingValidatorsTable } from './standby-pending-validators-table';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { formatNumber } from '../../../../lib/format-number';
|
||||
import {
|
||||
createDocsLinks,
|
||||
removePaginationWrapper,
|
||||
toBigNum,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { Link as UTLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { Link as UTLink, Toggle } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
import { formatNumber } from '../../../../lib/format-number';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
||||
import type {
|
||||
NodesQuery,
|
||||
NodesFragmentFragment,
|
||||
} from '../__generated___/Nodes';
|
||||
import type { PreviousEpochQuery } from '../../__generated___/PreviousEpoch';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { addUserDataToValidator } from './shared';
|
||||
import { ConsensusValidatorsTable } from './consensus-validators-table';
|
||||
import { StandbyPendingValidatorsTable } from './standby-pending-validators-table';
|
||||
import type { NodesQuery, NodesFragmentFragment } from '../__generated__/Nodes';
|
||||
import type { PreviousEpochQuery } from '../../__generated__/PreviousEpoch';
|
||||
import type { StakingQuery } from '../../__generated__/Staking';
|
||||
import type { StakingDelegationFieldsFragment } from '../../__generated__/Staking';
|
||||
import type { ValidatorWithUserData } from './shared';
|
||||
|
||||
export interface ValidatorsTableProps {
|
||||
data: NodesQuery | undefined;
|
||||
nodesData: NodesQuery | undefined;
|
||||
userStakingData: StakingQuery | undefined;
|
||||
previousEpochData: PreviousEpochQuery | undefined;
|
||||
}
|
||||
|
||||
@@ -31,8 +34,11 @@ interface SortedValidatorsProps {
|
||||
pendingValidators: NodesFragmentFragment[];
|
||||
}
|
||||
|
||||
export type ValidatorsView = 'all' | 'myStake';
|
||||
|
||||
export const ValidatorTables = ({
|
||||
data,
|
||||
nodesData,
|
||||
userStakingData,
|
||||
previousEpochData,
|
||||
}: ValidatorsTableProps) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -40,25 +46,69 @@ export const ValidatorTables = ({
|
||||
const {
|
||||
appState: { decimals },
|
||||
} = useAppState();
|
||||
|
||||
const [validatorsView, setValidatorsView] = useState<ValidatorsView>('all');
|
||||
const totalStake = useMemo(
|
||||
() => data?.nodeData?.stakedTotal || '0',
|
||||
[data?.nodeData?.stakedTotal]
|
||||
() => nodesData?.nodeData?.stakedTotal || '0',
|
||||
[nodesData?.nodeData?.stakedTotal]
|
||||
);
|
||||
const epochId = useMemo(() => nodesData?.epoch.id, [nodesData?.epoch.id]);
|
||||
const currentUserStakeAvailable = useMemo(
|
||||
() => userStakingData?.party?.stakingSummary.currentStakeAvailable || '0',
|
||||
[userStakingData?.party?.stakingSummary.currentStakeAvailable]
|
||||
);
|
||||
|
||||
let stakeNeededForPromotion = undefined;
|
||||
let delegations: StakingDelegationFieldsFragment[] | undefined = undefined;
|
||||
|
||||
if (userStakingData) {
|
||||
delegations = removePaginationWrapper(
|
||||
userStakingData?.party?.delegationsConnection?.edges
|
||||
);
|
||||
}
|
||||
|
||||
const { consensusValidators, standbyValidators, pendingValidators } = useMemo(
|
||||
() =>
|
||||
removePaginationWrapper(data?.nodesConnection.edges).reduce(
|
||||
removePaginationWrapper(nodesData?.nodesConnection.edges).reduce(
|
||||
(acc: SortedValidatorsProps, validator) => {
|
||||
const validatorId = validator.id;
|
||||
const currentDelegation = delegations?.find(
|
||||
(d) => d.node.id === validatorId && d.epoch === Number(epochId)
|
||||
);
|
||||
const nextDelegation = delegations?.find(
|
||||
(d) => d.node.id === validatorId && d.epoch === Number(epochId) + 1
|
||||
);
|
||||
|
||||
switch (validator.rankingScore?.status) {
|
||||
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT:
|
||||
acc.consensusValidators.push(validator);
|
||||
acc.consensusValidators.push(
|
||||
addUserDataToValidator(
|
||||
validator,
|
||||
currentDelegation,
|
||||
nextDelegation,
|
||||
currentUserStakeAvailable
|
||||
)
|
||||
);
|
||||
break;
|
||||
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_ERSATZ:
|
||||
acc.standbyValidators.push(validator);
|
||||
acc.standbyValidators.push(
|
||||
addUserDataToValidator(
|
||||
validator,
|
||||
currentDelegation,
|
||||
nextDelegation,
|
||||
currentUserStakeAvailable
|
||||
)
|
||||
);
|
||||
break;
|
||||
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_PENDING:
|
||||
acc.pendingValidators.push(validator);
|
||||
acc.pendingValidators.push(
|
||||
addUserDataToValidator(
|
||||
validator,
|
||||
currentDelegation,
|
||||
nextDelegation,
|
||||
currentUserStakeAvailable
|
||||
)
|
||||
);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
@@ -68,7 +118,12 @@ export const ValidatorTables = ({
|
||||
pendingValidators: [],
|
||||
}
|
||||
),
|
||||
[data?.nodesConnection.edges]
|
||||
[
|
||||
currentUserStakeAvailable,
|
||||
delegations,
|
||||
epochId,
|
||||
nodesData?.nodesConnection.edges,
|
||||
]
|
||||
);
|
||||
|
||||
if (
|
||||
@@ -76,7 +131,7 @@ export const ValidatorTables = ({
|
||||
(standbyValidators.length || pendingValidators.length)
|
||||
) {
|
||||
const lowestRankingConsensusScore = consensusValidators.reduce(
|
||||
(lowest: NodesFragmentFragment, validator: NodesFragmentFragment) => {
|
||||
(lowest: ValidatorWithUserData, validator: ValidatorWithUserData) => {
|
||||
if (
|
||||
Number(validator.rankingScore.rankingScore) <
|
||||
Number(lowest.rankingScore.rankingScore)
|
||||
@@ -98,19 +153,42 @@ export const ValidatorTables = ({
|
||||
).toString();
|
||||
}
|
||||
return (
|
||||
<div data-testid="validator-tables">
|
||||
<section data-testid="validator-tables">
|
||||
<div className="grid w-full justify-end">
|
||||
<div className="w-[400px]">
|
||||
<Toggle
|
||||
name="validators-view-toggle"
|
||||
toggles={[
|
||||
{
|
||||
label: t('ALL VALIDATORS'),
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
label: t('STAKED BY ME'),
|
||||
value: 'myStake',
|
||||
},
|
||||
]}
|
||||
checkedValue={validatorsView}
|
||||
onChange={(e) =>
|
||||
setValidatorsView(e.target.value as ValidatorsView)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{consensusValidators.length > 0 && (
|
||||
<>
|
||||
<div className="mb-10">
|
||||
<SubHeading title={t('status-tendermint')} />
|
||||
<ConsensusValidatorsTable
|
||||
data={consensusValidators}
|
||||
previousEpochData={previousEpochData}
|
||||
totalStake={totalStake}
|
||||
validatorsView={validatorsView}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
{standbyValidators.length > 0 && (
|
||||
<>
|
||||
<div className="mb-10">
|
||||
<SubHeading title={t('status-ersatz')} />
|
||||
<p>
|
||||
<Trans
|
||||
@@ -126,8 +204,9 @@ export const ValidatorTables = ({
|
||||
totalStake={totalStake}
|
||||
stakeNeededForPromotion={stakeNeededForPromotion}
|
||||
stakeNeededForPromotionDescription="StakeNeededForPromotionStandbyDescription"
|
||||
validatorsView={validatorsView}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
{pendingValidators.length > 0 && (
|
||||
<>
|
||||
@@ -155,9 +234,10 @@ export const ValidatorTables = ({
|
||||
totalStake={totalStake}
|
||||
stakeNeededForPromotion={stakeNeededForPromotion}
|
||||
stakeNeededForPromotionDescription="StakeNeededForPromotionCandidateDescription"
|
||||
validatorsView={validatorsView}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -20,8 +20,8 @@ import NodeContainer from './nodes-container';
|
||||
import { useAppState } from '../../../contexts/app-state/app-state-context';
|
||||
import { Heading, SubHeading } from '../../../components/heading';
|
||||
import Routes from '../../routes';
|
||||
import type { StakingQuery } from './__generated__/Staking';
|
||||
import type { PreviousEpochQuery } from '../__generated___/PreviousEpoch';
|
||||
import type { StakingQuery } from '../__generated__/Staking';
|
||||
import type { PreviousEpochQuery } from '../__generated__/PreviousEpoch';
|
||||
|
||||
interface StakingNodeProps {
|
||||
data?: StakingQuery;
|
||||
@@ -116,13 +116,6 @@ export const StakingNode = ({ data, previousEpochData }: StakingNodeProps) => {
|
||||
t('validatorTitle', { nodeName: t('validatorTitleFallback') })
|
||||
}
|
||||
/>
|
||||
<section className="mb-4">
|
||||
<ValidatorTable
|
||||
node={nodeInfo}
|
||||
stakedTotal={addDecimal(data?.nodeData?.stakedTotal || '0', decimals)}
|
||||
previousEpochData={previousEpochData}
|
||||
/>
|
||||
</section>
|
||||
{data?.epoch.timestamps.start && data?.epoch.timestamps.expiry && (
|
||||
<section className="mb-10">
|
||||
<EpochCountdown
|
||||
@@ -157,6 +150,13 @@ export const StakingNode = ({ data, previousEpochData }: StakingNodeProps) => {
|
||||
<ConnectToVega />
|
||||
</>
|
||||
)}
|
||||
<section className="mb-4">
|
||||
<ValidatorTable
|
||||
node={nodeInfo}
|
||||
stakedTotal={addDecimal(data?.nodeData?.stakedTotal || '0', decimals)}
|
||||
previousEpochData={previousEpochData}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,11 +4,11 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
|
||||
import { SplashLoader } from '../../../components/splash-loader';
|
||||
import { useStakingQuery } from './__generated__/Staking';
|
||||
import { usePreviousEpochQuery } from '../__generated___/PreviousEpoch';
|
||||
import { useStakingQuery } from '../__generated__/Staking';
|
||||
import { usePreviousEpochQuery } from '../__generated__/PreviousEpoch';
|
||||
import type { ReactElement } from 'react';
|
||||
import type { StakingQuery } from './__generated__/Staking';
|
||||
import type { PreviousEpochQuery } from '../__generated___/PreviousEpoch';
|
||||
import type { StakingQuery } from '../__generated__/Staking';
|
||||
import type { PreviousEpochQuery } from '../__generated__/PreviousEpoch';
|
||||
|
||||
// TODO should only request a single node. When migrating from deprecated APIs we should address this.
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import { SubHeading } from '../../../components/heading';
|
||||
import {
|
||||
getLastEpochScoreAndPerformance,
|
||||
getNormalisedVotingPower,
|
||||
getOverstakedAmount,
|
||||
getOverstakingPenalty,
|
||||
getPerformancePenalty,
|
||||
getTotalPenalties,
|
||||
@@ -28,8 +27,8 @@ import {
|
||||
getStakePercentage,
|
||||
} from '../shared';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { StakingNodeFieldsFragment } from './__generated__/Staking';
|
||||
import type { PreviousEpochQuery } from '../__generated___/PreviousEpoch';
|
||||
import type { StakingNodeFieldsFragment } from '../__generated__/Staking';
|
||||
import type { PreviousEpochQuery } from '../__generated__/PreviousEpoch';
|
||||
|
||||
const statuses = {
|
||||
[Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_ERSATZ]: 'status-ersatz',
|
||||
@@ -75,15 +74,9 @@ export const ValidatorTable = ({
|
||||
|
||||
const stakedOnNode = toBigNum(node.stakedTotal, decimals);
|
||||
|
||||
const { rawValidatorScore, performanceScore } =
|
||||
const { rawValidatorScore, performanceScore, stakeScore } =
|
||||
getLastEpochScoreAndPerformance(previousEpochData, node.id);
|
||||
|
||||
const overstakedAmount = getOverstakedAmount(
|
||||
rawValidatorScore,
|
||||
stakedTotal,
|
||||
node.stakedTotal
|
||||
);
|
||||
|
||||
const stakePercentage = getStakePercentage(total, stakedOnNode);
|
||||
|
||||
const totalPenaltiesAmount = getTotalPenalties(
|
||||
@@ -111,7 +104,7 @@ export const ValidatorTable = ({
|
||||
|
||||
<div className="my-12" data-testid="validator-table">
|
||||
<SubHeading title={t('profile')} />
|
||||
<RoundedWrapper>
|
||||
<RoundedWrapper paddingBottom={true}>
|
||||
<KeyValueTable data-testid="validator-table-profile">
|
||||
<KeyValueTableRow>
|
||||
<span>{t('id')}</span>
|
||||
@@ -156,7 +149,7 @@ export const ValidatorTable = ({
|
||||
</div>
|
||||
|
||||
<SubHeading title={t('ADDRESS')} />
|
||||
<RoundedWrapper marginBottomLarge={true}>
|
||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||
<KeyValueTable data-testid="validator-table-address">
|
||||
<KeyValueTableRow>
|
||||
<span>{t('VEGA ADDRESS / PUBLIC KEY')}</span>
|
||||
@@ -187,7 +180,7 @@ export const ValidatorTable = ({
|
||||
</RoundedWrapper>
|
||||
|
||||
<SubHeading title={t('STAKE')} />
|
||||
<RoundedWrapper marginBottomLarge={true}>
|
||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||
<KeyValueTable data-testid="validator-table-stake">
|
||||
<KeyValueTableRow>
|
||||
<span>{t('STAKED BY OPERATOR')}</span>
|
||||
@@ -238,14 +231,14 @@ export const ValidatorTable = ({
|
||||
</RoundedWrapper>
|
||||
|
||||
<SubHeading title={t('PENALTIES')} />
|
||||
<RoundedWrapper marginBottomLarge={true}>
|
||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||
<KeyValueTable data-testid="validator-table-penalties">
|
||||
<KeyValueTableRow>
|
||||
<span>{t('OVERSTAKED PENALTY')}</span>
|
||||
|
||||
<Tooltip description={t('OverstakedPenaltyDescription')}>
|
||||
<span data-testid="overstaking-penalty">
|
||||
{getOverstakingPenalty(overstakedAmount, node.stakedTotal)}
|
||||
{getOverstakingPenalty(rawValidatorScore, stakeScore)}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</KeyValueTableRow>
|
||||
@@ -270,7 +263,7 @@ export const ValidatorTable = ({
|
||||
</RoundedWrapper>
|
||||
|
||||
<SubHeading title={t('VOTING POWER')} />
|
||||
<RoundedWrapper marginBottomLarge={true}>
|
||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||
<KeyValueTable data-testid="validator-table-voting-power">
|
||||
<KeyValueTableRow>
|
||||
<span>{t('UNNORMALISED VOTING POWER')}</span>
|
||||
|
||||
@@ -23,7 +23,7 @@ export const YourStake = ({
|
||||
return (
|
||||
<div data-testid="your-stake">
|
||||
<SubHeading title={t('Your stake')} />
|
||||
<RoundedWrapper>
|
||||
<RoundedWrapper paddingBottom={true}>
|
||||
<KeyValueTable>
|
||||
<KeyValueTableRow>
|
||||
{t('Your Stake On Node (This Epoch)')}
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
getNormalisedVotingPower,
|
||||
getUnnormalisedVotingPower,
|
||||
getOverstakingPenalty,
|
||||
getOverstakedAmount,
|
||||
getFormattedPerformanceScore,
|
||||
getPerformancePenalty,
|
||||
getTotalPenalties,
|
||||
@@ -22,9 +21,10 @@ describe('getLastEpochScoreAndPerformance', () => {
|
||||
id: '0x123',
|
||||
rewardScore: {
|
||||
rawValidatorScore: '0.25',
|
||||
performanceScore: '0.75',
|
||||
},
|
||||
rankingScore: {
|
||||
performanceScore: '0.75',
|
||||
stakeScore: '0.25',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -33,9 +33,10 @@ describe('getLastEpochScoreAndPerformance', () => {
|
||||
id: '0x234',
|
||||
rewardScore: {
|
||||
rawValidatorScore: '0.35',
|
||||
performanceScore: '0.85',
|
||||
},
|
||||
rankingScore: {
|
||||
performanceScore: '0.85',
|
||||
stakeScore: '0.25',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -50,12 +51,14 @@ describe('getLastEpochScoreAndPerformance', () => {
|
||||
).toEqual({
|
||||
rawValidatorScore: '0.25',
|
||||
performanceScore: '0.75',
|
||||
stakeScore: '0.25',
|
||||
});
|
||||
expect(
|
||||
getLastEpochScoreAndPerformance(mockPreviousEpochData, '0x234')
|
||||
).toEqual({
|
||||
rawValidatorScore: '0.35',
|
||||
performanceScore: '0.85',
|
||||
stakeScore: '0.25',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -79,40 +82,34 @@ describe('getUnnormalisedVotingPower', () => {
|
||||
});
|
||||
|
||||
describe('getOverstakingPenalty', () => {
|
||||
it('should return the overstaking penalty', () => {
|
||||
expect(
|
||||
getOverstakingPenalty(new BigNumber(100), Number(1000).toString())
|
||||
).toEqual('10.00%');
|
||||
expect(
|
||||
getOverstakingPenalty(new BigNumber(500), Number(2000).toString())
|
||||
).toEqual('25.00%');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOverstakedAmount', () => {
|
||||
it('should return the overstaked amount', () => {
|
||||
expect(
|
||||
// If a validator score is 0, any amount staked on the node is considered overstaked
|
||||
getOverstakedAmount('0', Number(100).toString(), Number(20).toString())
|
||||
).toEqual(new BigNumber(20));
|
||||
expect(
|
||||
getOverstakedAmount('0.05', Number(100).toString(), Number(20).toString())
|
||||
).toEqual(new BigNumber(15));
|
||||
expect(
|
||||
getOverstakedAmount('0.1', Number(100).toString(), Number(20).toString())
|
||||
).toEqual(new BigNumber(10));
|
||||
expect(
|
||||
getOverstakedAmount('0.15', Number(100).toString(), Number(20).toString())
|
||||
).toEqual(new BigNumber(5));
|
||||
expect(
|
||||
getOverstakedAmount('0.2', Number(100).toString(), Number(20).toString())
|
||||
).toEqual(new BigNumber(0));
|
||||
it('returns "0%" when both arguments are null or undefined', () => {
|
||||
expect(getOverstakingPenalty(null, null)).toBe('0%');
|
||||
expect(getOverstakingPenalty(undefined, undefined)).toBe('0%');
|
||||
expect(getOverstakingPenalty(null, undefined)).toBe('0%');
|
||||
expect(getOverstakingPenalty(undefined, null)).toBe('0%');
|
||||
});
|
||||
|
||||
it('should return 0 if the overstaked amount is negative', () => {
|
||||
expect(
|
||||
getOverstakedAmount('0.8', Number(100).toString(), Number(20).toString())
|
||||
).toEqual(new BigNumber(0));
|
||||
it('returns "0%" when one argument is null or undefined', () => {
|
||||
expect(getOverstakingPenalty('10', null)).toBe('0%');
|
||||
expect(getOverstakingPenalty(null, '20')).toBe('0%');
|
||||
expect(getOverstakingPenalty('10', undefined)).toBe('0%');
|
||||
expect(getOverstakingPenalty(undefined, '20')).toBe('0%');
|
||||
});
|
||||
|
||||
it('returns "0%" when validatorScore or stakeScore is zero', () => {
|
||||
expect(getOverstakingPenalty('0', '20')).toBe('0%');
|
||||
expect(getOverstakingPenalty('10', '0')).toBe('0%');
|
||||
});
|
||||
|
||||
it('returns the correct overstaking penalty', () => {
|
||||
expect(getOverstakingPenalty('0.18', '0.2')).toBe('10.00%');
|
||||
expect(getOverstakingPenalty('0.2', '0.2')).toBe('0.00%');
|
||||
expect(getOverstakingPenalty('0.04', '0.2')).toBe('80.00%');
|
||||
});
|
||||
|
||||
it('handles string numbers with decimals', () => {
|
||||
expect(getOverstakingPenalty('7.5', '15')).toBe('50.00%');
|
||||
expect(getOverstakingPenalty('12.5', '25')).toBe('50.00%');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
formatNumberPercentage,
|
||||
removePaginationWrapper,
|
||||
} from '@vegaprotocol/utils';
|
||||
import type { PreviousEpochQuery } from './__generated___/PreviousEpoch';
|
||||
import type { PreviousEpochQuery } from './__generated__/PreviousEpoch';
|
||||
import { BigNumber } from '../../lib/bignumber';
|
||||
|
||||
export const getLastEpochScoreAndPerformance = (
|
||||
@@ -15,7 +15,8 @@ export const getLastEpochScoreAndPerformance = (
|
||||
|
||||
return {
|
||||
rawValidatorScore: validator?.rewardScore?.rawValidatorScore,
|
||||
performanceScore: validator?.rankingScore?.performanceScore,
|
||||
performanceScore: validator?.rewardScore?.performanceScore,
|
||||
stakeScore: validator?.rankingScore?.stakeScore,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -42,31 +43,26 @@ export const getPerformancePenalty = (performanceScore?: string) =>
|
||||
2
|
||||
);
|
||||
|
||||
export const getOverstakedAmount = (
|
||||
validatorScore: string | null | undefined,
|
||||
totalStake: string,
|
||||
stakedOnNode: string
|
||||
) => {
|
||||
const toReturn = validatorScore
|
||||
? new BigNumber(stakedOnNode).minus(
|
||||
new BigNumber(validatorScore).times(new BigNumber(totalStake))
|
||||
)
|
||||
: new BigNumber(0);
|
||||
|
||||
return toReturn.isNegative() ? new BigNumber(0) : toReturn;
|
||||
};
|
||||
|
||||
export const getOverstakingPenalty = (
|
||||
overstakedAmount: BigNumber,
|
||||
stakedOnNode: string
|
||||
validatorScore: string | null | undefined,
|
||||
stakeScore: string | null | undefined
|
||||
) => {
|
||||
if (!validatorScore || !stakeScore) {
|
||||
return '0%';
|
||||
}
|
||||
|
||||
// avoid division by zero
|
||||
if (new BigNumber(stakedOnNode).isZero() || overstakedAmount.isZero()) {
|
||||
return '0';
|
||||
if (
|
||||
new BigNumber(validatorScore).isZero() ||
|
||||
new BigNumber(stakeScore).isZero()
|
||||
) {
|
||||
return '0%';
|
||||
}
|
||||
|
||||
return formatNumberPercentage(
|
||||
overstakedAmount.dividedBy(new BigNumber(stakedOnNode)).times(100),
|
||||
new BigNumber(1)
|
||||
.minus(new BigNumber(validatorScore).dividedBy(new BigNumber(stakeScore)))
|
||||
.times(100),
|
||||
2
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@ import { TokenDetailsCirculating } from './token-details-circulating';
|
||||
import { SplashLoader } from '../../../components/splash-loader';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import { useContracts } from '../../../contexts/contracts/contracts-context';
|
||||
import { ENV } from '../../../config';
|
||||
|
||||
export const TokenDetails = ({
|
||||
totalSupply,
|
||||
@@ -49,6 +50,9 @@ export const TokenDetails = ({
|
||||
);
|
||||
}
|
||||
|
||||
const tokenVestingContractAddress =
|
||||
config.token_vesting_contract?.address || ENV.addresses.tokenVestingAddress;
|
||||
|
||||
return (
|
||||
<div className="token-details">
|
||||
<RoundedWrapper>
|
||||
@@ -65,18 +69,20 @@ export const TokenDetails = ({
|
||||
{token.address}
|
||||
</Link>
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow>
|
||||
{t('Vesting contract').toUpperCase()}
|
||||
<Link
|
||||
data-testid="token-contract"
|
||||
title={t('View on Etherscan (opens in a new tab)')}
|
||||
className="font-mono text-white text-right"
|
||||
href={`${ETHERSCAN_URL}/address/${config.token_vesting_contract.address}`}
|
||||
target="_blank"
|
||||
>
|
||||
{config.token_vesting_contract.address}
|
||||
</Link>
|
||||
</KeyValueTableRow>
|
||||
{tokenVestingContractAddress && (
|
||||
<KeyValueTableRow>
|
||||
{t('Vesting contract').toUpperCase()}
|
||||
<Link
|
||||
data-testid="token-contract"
|
||||
title={t('View on Etherscan (opens in a new tab)')}
|
||||
className="font-mono text-white text-right"
|
||||
href={`${ETHERSCAN_URL}/address/${tokenVestingContractAddress}`}
|
||||
target="_blank"
|
||||
>
|
||||
{tokenVestingContractAddress}
|
||||
</Link>
|
||||
</KeyValueTableRow>
|
||||
)}
|
||||
<KeyValueTableRow>
|
||||
{t('Total supply').toUpperCase()}
|
||||
<span className="font-mono" data-testid="total-supply">
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/sandbox/vegawallet-sandbox.toml
|
||||
NX_VEGA_URL=https://api.sandbox.vega.xyz/graphql
|
||||
NX_VEGA_ENV=SANDBOX
|
||||
NX_VEGA_NETWORKS={\"DEVNET\":\"https://dev.token.vega.xyz\",\"STAGNET3\":\"https://stagnet3.token.vega.xyz\",\"STAGNET1\":\"https://stagnet1.token.vega.xyz\",\"TESTNET\":\"https://token.fairground.wtf\",\"MAINNET\":\"https://token.vega.xyz\"}
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/sandbox/vegawallet-sandbox.toml
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"hosts": ["https://api-n00.mainnet-mirror.vega.rocks/graphql"]
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"hosts": ["https://api-n01.sandbox.vega.rocks/graphql"]
|
||||
}
|
||||
@@ -19,6 +19,7 @@ CYPRESS_ETHEREUM_WALLET_ADDRESS=0xEe7D375bcB50C26d52E1A4a472D8822A2A22d94F
|
||||
CYPRESS_ETHEREUM_PROVIDER_URL=http://localhost:8545
|
||||
CYPRESS_EXPLORER_URL=https://explorer.fairground.wtf
|
||||
CYPRESS_FAUCET_URL=http://localhost:1790/api/v1/mint
|
||||
CYPRESS_ORACLE_PUBKEY=6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61
|
||||
CYPRESS_TRUNCATED_VEGA_PUBLIC_KEY=02ecea…342f65
|
||||
CYPRESS_TRUNCATED_VEGA_PUBLIC_KEY2=7f9cf0…c25535
|
||||
CYPRESS_VEGA_ENV=CUSTOM
|
||||
|
||||
@@ -282,7 +282,6 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
// comment because of bug #2695
|
||||
it('can edit order', function () {
|
||||
cy.getByTestId(ordersTab).click();
|
||||
cy.getByTestId('edit').first().should('be.visible').click();
|
||||
|
||||
@@ -87,7 +87,10 @@ describe('deposit form validation', { tags: '@smoke' }, () => {
|
||||
.clear()
|
||||
.type('850')
|
||||
.next(`[data-testid="${formFieldError}"]`)
|
||||
.should('have.text', 'Insufficient amount in Ethereum wallet');
|
||||
.should(
|
||||
'have.text',
|
||||
"You can't deposit more than you have in your Ethereum wallet, 800 tEURO"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ describe('Console - market list - live env', { tags: '@live' }, () => {
|
||||
describe('Console - market info - live env', { tags: '@live' }, () => {
|
||||
before(() => {
|
||||
cy.visit('/');
|
||||
cy.contains('Loading market data...').should('not.exist');
|
||||
cy.getByTestId('link').should('be.visible');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
cy.getByTestId(marketInfoBtn).click();
|
||||
});
|
||||
@@ -68,17 +70,20 @@ describe('Console - market info - live env', { tags: '@live' }, () => {
|
||||
'Risk model',
|
||||
'Risk parameters',
|
||||
'Risk factors',
|
||||
'Price monitoring trigger 1',
|
||||
'Price monitoring bounds 1',
|
||||
'Liquidity monitoring parameters',
|
||||
'Liquidity',
|
||||
'Liquidity price range',
|
||||
'Oracle',
|
||||
'Proposal',
|
||||
];
|
||||
|
||||
it('market info titles are displayed', () => {
|
||||
cy.get('.text-lg').each((element, index) => {
|
||||
cy.wrap(element).should('have.text', titles[index]);
|
||||
});
|
||||
cy.getByTestId('split-view-view')
|
||||
.find('.text-lg')
|
||||
.each((element, index) => {
|
||||
cy.wrap(element).should('have.text', titles[index]);
|
||||
});
|
||||
});
|
||||
|
||||
it('market info subtitles are displayed', () => {
|
||||
@@ -90,6 +95,16 @@ describe('Console - market info - live env', { tags: '@live' }, () => {
|
||||
cy.wrap(element).should('have.text', subtitles[index]);
|
||||
});
|
||||
});
|
||||
|
||||
it('renders correctly liquidity in trading tab', () => {
|
||||
cy.getByTestId('Liquidity').click();
|
||||
cy.contains('Loading').should('not.exist');
|
||||
cy.contains('Something went wrong').should('not.exist');
|
||||
cy.contains('Application error').should('not.exist');
|
||||
cy.getByTestId('tab-liquidity').within(() => {
|
||||
cy.get('[col-id="party.id"]').eq(1).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Console - market summary - live env', { tags: '@live' }, () => {
|
||||
@@ -205,6 +220,8 @@ describe('Console - markets table - live env', { tags: '@live' }, () => {
|
||||
});
|
||||
|
||||
function openMarketDropDown() {
|
||||
cy.contains('Loading...').should('not.exist');
|
||||
cy.getByTestId('link').should('be.visible');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
cy.getByTestId('popover-trigger').click();
|
||||
cy.contains('Loading market data...').should('not.exist');
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
it('market volume displayed', () => {
|
||||
cy.getByTestId(marketTitle).contains('Market volume').click();
|
||||
validateMarketDataRow(0, '24 Hour Volume', '1');
|
||||
validateMarketDataRow(1, 'Open Interest', '0');
|
||||
validateMarketDataRow(1, 'Open Interest', '-');
|
||||
validateMarketDataRow(2, 'Best Bid Volume', '1');
|
||||
validateMarketDataRow(3, 'Best Offer Volume', '3');
|
||||
validateMarketDataRow(4, 'Best Static Bid Volume', '2');
|
||||
@@ -75,8 +75,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
validateMarketDataRow(3, 'Quote Name', 'BTC');
|
||||
});
|
||||
|
||||
// need to check why data are not visible
|
||||
it.skip('settlement asset displayed', () => {
|
||||
it('settlement asset displayed', () => {
|
||||
cy.getByTestId(marketTitle).contains('Settlement asset').click();
|
||||
cy.window().then((win) => {
|
||||
cy.stub(win, 'prompt').returns('DISABLED WINDOW PROMPT');
|
||||
@@ -181,7 +180,15 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
'termination.BTC.value'
|
||||
);
|
||||
|
||||
// check that links to github for oracle proofs are shown
|
||||
cy.getByTestId(accordionContent)
|
||||
.getByTestId('oracle-proof-links')
|
||||
.find(`[data-testid="${externalLink}"]`)
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://github.com/vegaprotocol/well-known');
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.getByTestId('oracle-spec-links')
|
||||
.find(`[data-testid="${externalLink}"]`)
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/oracles');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { aliasGQLQuery, checkSorting } from '@vegaprotocol/cypress';
|
||||
import { marketsQuery } from '@vegaprotocol/mock';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||
|
||||
@@ -85,6 +85,7 @@ describe('markets table', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId('view-market-list-link')
|
||||
.should('have.attr', 'href', '#/markets/all')
|
||||
.click();
|
||||
|
||||
cy.get('[data-testid="All markets"]').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
@@ -117,6 +118,85 @@ describe('markets table', { tags: '@smoke' }, () => {
|
||||
`${Cypress.env('VEGA_TOKEN_URL')}/proposals/propose/new-market`
|
||||
);
|
||||
});
|
||||
it('proposed markets tab should be sorted properly', () => {
|
||||
cy.getByTestId('view-market-list-link').click();
|
||||
cy.get('[data-testid="Proposed markets"]').click();
|
||||
const marketColDefault = [
|
||||
'ETHUSD',
|
||||
'LINKUSD',
|
||||
'ETHUSD',
|
||||
'ETHDAI.MF21',
|
||||
'AAPL.MF21',
|
||||
'BTCUSD.MF21',
|
||||
'TSLA.QM21',
|
||||
'AAVEDAI.MF21',
|
||||
'ETHBTC.QM21',
|
||||
'UNIDAI.MF21',
|
||||
];
|
||||
const marketColAsc = [
|
||||
'AAPL.MF21',
|
||||
'AAVEDAI.MF21',
|
||||
'BTCUSD.MF21',
|
||||
'ETHBTC.QM21',
|
||||
'ETHDAI.MF21',
|
||||
'ETHUSD',
|
||||
'ETHUSD',
|
||||
'LINKUSD',
|
||||
'TSLA.QM21',
|
||||
'UNIDAI.MF21',
|
||||
];
|
||||
const marketColDesc = [
|
||||
'UNIDAI.MF21',
|
||||
'TSLA.QM21',
|
||||
'LINKUSD',
|
||||
'ETHUSD',
|
||||
'ETHUSD',
|
||||
'ETHDAI.MF21',
|
||||
'ETHBTC.QM21',
|
||||
'BTCUSD.MF21',
|
||||
'AAVEDAI.MF21',
|
||||
'AAPL.MF21',
|
||||
];
|
||||
checkSorting('market', marketColDefault, marketColAsc, marketColDesc);
|
||||
|
||||
const stateColDefault = [
|
||||
'Open',
|
||||
'Passed',
|
||||
'Waiting for Node Vote',
|
||||
'Open',
|
||||
'Passed',
|
||||
'Open',
|
||||
'Passed',
|
||||
'Open',
|
||||
'Waiting for Node Vote',
|
||||
'Open',
|
||||
];
|
||||
const stateColAsc = [
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
'Passed',
|
||||
'Passed',
|
||||
'Passed',
|
||||
'Waiting for Node Vote',
|
||||
'Waiting for Node Vote',
|
||||
];
|
||||
const stateColDesc = [
|
||||
'Waiting for Node Vote',
|
||||
'Waiting for Node Vote',
|
||||
'Passed',
|
||||
'Passed',
|
||||
'Passed',
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
'Open',
|
||||
];
|
||||
checkSorting('state', stateColDefault, stateColAsc, stateColDesc);
|
||||
});
|
||||
|
||||
it('opening auction subsets should be properly displayed', () => {
|
||||
cy.mockTradingPage(
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
describe('chart', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
it('config should persist', () => {
|
||||
cy.getByTestId('Chart').click();
|
||||
cy.get('[data-testid="tab-chart"] button').as('control-buttons');
|
||||
cy.get('@control-buttons').each(($button) => {
|
||||
cy.wrap($button).click();
|
||||
cy.get(
|
||||
'[role="menuitemradio"]:first, [role="menuitemcheckbox"]:first'
|
||||
).click();
|
||||
});
|
||||
cy.getByTestId('Depth').click();
|
||||
cy.getByTestId('Chart').click();
|
||||
cy.get('@control-buttons').each(($button) => {
|
||||
cy.wrap($button).click();
|
||||
cy.get('[role="menuitemradio"]:first, [role="menuitemcheckbox"]:first')
|
||||
.within(($lastMenuItem) => {
|
||||
expect($lastMenuItem.data('state')).to.equal('checked');
|
||||
})
|
||||
.click();
|
||||
});
|
||||
});
|
||||
});
|
||||
+33
-252
@@ -1,5 +1,5 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { aliasGQLQuery, mockConnectWallet } from '@vegaprotocol/cypress';
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { testOrderSubmission } from '../support/order-validation';
|
||||
import type { OrderSubmission } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
@@ -13,8 +13,6 @@ const orderSizeField = 'order-size';
|
||||
const orderPriceField = 'order-price';
|
||||
const orderTIFDropDown = 'order-tif';
|
||||
const placeOrderBtn = 'place-order';
|
||||
const toggleShort = 'order-side-SIDE_SELL';
|
||||
const toggleLong = 'order-side-SIDE_BUY';
|
||||
const toggleLimit = 'order-type-TYPE_LIMIT';
|
||||
const toggleMarket = 'order-type-TYPE_MARKET';
|
||||
|
||||
@@ -32,34 +30,6 @@ const displayTomorrow = () => {
|
||||
return tomorrow.toISOString().substring(0, 16);
|
||||
};
|
||||
|
||||
describe('time in force default values', () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('must have market order set up to IOC by default', function () {
|
||||
// 7002-SORD-031
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
TIFlist.filter((item) => item.code === 'IOC')[0].text
|
||||
);
|
||||
});
|
||||
|
||||
it('must have time in force set to GTC for limit order', function () {
|
||||
// 7002-SORD-031
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
TIFlist.filter((item) => item.code === 'GTC')[0].text
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('must submit order', { tags: '@smoke' }, () => {
|
||||
// 7002-SORD-039
|
||||
before(() => {
|
||||
@@ -84,6 +54,8 @@ describe('must submit order', { tags: '@smoke' }, () => {
|
||||
type: Schema.OrderType.TYPE_MARKET,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
size: '100',
|
||||
};
|
||||
createOrder(order);
|
||||
@@ -98,6 +70,8 @@ describe('must submit order', { tags: '@smoke' }, () => {
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
};
|
||||
createOrder(order);
|
||||
testOrderSubmission(order);
|
||||
@@ -112,6 +86,8 @@ describe('must submit order', { tags: '@smoke' }, () => {
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
price: '200',
|
||||
};
|
||||
createOrder(order);
|
||||
@@ -126,6 +102,8 @@ describe('must submit order', { tags: '@smoke' }, () => {
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GFN,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
price: '50000',
|
||||
};
|
||||
createOrder(order);
|
||||
@@ -143,6 +121,8 @@ describe('must submit order', { tags: '@smoke' }, () => {
|
||||
size: '100',
|
||||
price: '1.00',
|
||||
expiresAt: expiresAt.toISOString().substring(0, 16),
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
};
|
||||
|
||||
createOrder(order);
|
||||
@@ -150,6 +130,8 @@ describe('must submit order', { tags: '@smoke' }, () => {
|
||||
price: '100000',
|
||||
expiresAt:
|
||||
new Date(order.expiresAt as string).getTime().toString() + '000000',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -182,6 +164,8 @@ describe(
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
price: '200',
|
||||
};
|
||||
createOrder(order);
|
||||
@@ -196,6 +180,8 @@ describe(
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
price: '50000',
|
||||
};
|
||||
createOrder(order);
|
||||
@@ -210,12 +196,16 @@ describe(
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
price: '1.00',
|
||||
expiresAt: displayTomorrow(),
|
||||
};
|
||||
createOrder(order);
|
||||
testOrderSubmission(order, {
|
||||
price: '100000',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
expiresAt:
|
||||
new Date(order.expiresAt as string).getTime().toString() + '000000',
|
||||
});
|
||||
@@ -251,6 +241,8 @@ describe(
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
price: '200',
|
||||
};
|
||||
createOrder(order);
|
||||
@@ -265,6 +257,8 @@ describe(
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
price: '50000',
|
||||
};
|
||||
createOrder(order);
|
||||
@@ -281,6 +275,8 @@ describe(
|
||||
size: '100',
|
||||
price: '1.00',
|
||||
expiresAt: displayTomorrow(),
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
};
|
||||
createOrder(order);
|
||||
testOrderSubmission(order, {
|
||||
@@ -320,6 +316,8 @@ describe(
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
size: '100',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
price: '200',
|
||||
};
|
||||
createOrder(order);
|
||||
@@ -335,6 +333,8 @@ describe(
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
size: '100',
|
||||
price: '50000',
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
};
|
||||
createOrder(order);
|
||||
testOrderSubmission(order, { price: '5000000000' });
|
||||
@@ -350,6 +350,8 @@ describe(
|
||||
size: '100',
|
||||
price: '1.00',
|
||||
expiresAt: displayTomorrow(),
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
};
|
||||
createOrder(order);
|
||||
testOrderSubmission(order, {
|
||||
@@ -361,227 +363,6 @@ describe(
|
||||
}
|
||||
);
|
||||
|
||||
describe('deal ticket validation', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('must show place order button and connect wallet if wallet is not connected', () => {
|
||||
// 0003-WTXN-001
|
||||
cy.getByTestId('connect-vega-wallet'); // Not connected
|
||||
cy.getByTestId('order-connect-wallet').should('exist');
|
||||
cy.getByTestId(placeOrderBtn).should('exist');
|
||||
cy.getByTestId('deal-ticket-connect-wallet').should('exist');
|
||||
});
|
||||
|
||||
it('must be able to select order direction - long/short', function () {
|
||||
// 7002-SORD-004
|
||||
cy.getByTestId(toggleShort).click().children('input').should('be.checked');
|
||||
cy.getByTestId(toggleLong).click().children('input').should('be.checked');
|
||||
});
|
||||
|
||||
it('must be able to select order type - limit/market', function () {
|
||||
// 7002-SORD-005
|
||||
// 7002-SORD-006
|
||||
// 7002-SORD-007
|
||||
cy.getByTestId(toggleLimit).click().children('input').should('be.checked');
|
||||
cy.getByTestId(toggleMarket).click().children('input').should('be.checked');
|
||||
});
|
||||
|
||||
it('order connect vega wallet button should connect', () => {
|
||||
mockConnectWallet();
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.getByTestId(orderPriceField).clear().type('101');
|
||||
cy.getByTestId('order-connect-wallet').click();
|
||||
cy.getByTestId('dialog-content').should('be.visible');
|
||||
cy.getByTestId('connectors-list')
|
||||
.find('[data-testid="connector-jsonRpc"]')
|
||||
.click();
|
||||
cy.wait('@walletReq');
|
||||
cy.getByTestId(placeOrderBtn).should('be.visible');
|
||||
cy.getByTestId(toggleLimit).children('input').should('be.checked');
|
||||
cy.getByTestId(orderPriceField).should('have.value', '101');
|
||||
});
|
||||
});
|
||||
|
||||
describe('deal ticket size validation', { tags: '@smoke' }, function () {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('must warn if order size input has too many digits after the decimal place', function () {
|
||||
// 7002-SORD-016
|
||||
cy.getByTestId('order-type-TYPE_MARKET').click();
|
||||
cy.getByTestId(orderSizeField).clear().type('1.234');
|
||||
cy.getByTestId(placeOrderBtn).should('not.be.disabled');
|
||||
cy.getByTestId(placeOrderBtn).click();
|
||||
cy.getByTestId(placeOrderBtn).should('be.disabled');
|
||||
cy.getByTestId('dealticket-error-message-size-market').should(
|
||||
'have.text',
|
||||
'Size must be whole numbers for this market'
|
||||
);
|
||||
});
|
||||
|
||||
it('must warn if order size is set to 0', function () {
|
||||
cy.getByTestId('order-type-TYPE_MARKET').click();
|
||||
cy.getByTestId(orderSizeField).clear().type('0');
|
||||
cy.getByTestId(placeOrderBtn).should('not.be.disabled');
|
||||
cy.getByTestId(placeOrderBtn).click();
|
||||
cy.getByTestId(placeOrderBtn).should('be.disabled');
|
||||
cy.getByTestId('dealticket-error-message-size-market').should(
|
||||
'have.text',
|
||||
'Size cannot be lower than 1'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('limit order validations', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('must see the price unit', function () {
|
||||
// 7002-SORD-018
|
||||
cy.getByTestId(orderPriceField)
|
||||
.siblings('label')
|
||||
.should('have.text', 'Price (DAI)');
|
||||
});
|
||||
|
||||
it('must see warning when placing an order with expiry date in past', () => {
|
||||
const expiresAt = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
||||
const expiresAtInputValue = expiresAt.toISOString().substring(0, 16);
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.getByTestId(orderPriceField).clear().type('0.1');
|
||||
cy.getByTestId(orderSizeField).clear().type('1');
|
||||
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTT');
|
||||
|
||||
cy.log('choosing yesterday');
|
||||
cy.getByTestId('date-picker-field').type(expiresAtInputValue);
|
||||
|
||||
cy.getByTestId(placeOrderBtn).click();
|
||||
|
||||
cy.getByTestId('dealticket-error-message-expiry').should(
|
||||
'have.text',
|
||||
'The expiry date that you have entered appears to be in the past'
|
||||
);
|
||||
});
|
||||
|
||||
it('must see warning if price has too many digits after decimal place', function () {
|
||||
// 7002-SORD-059
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTC');
|
||||
cy.getByTestId(orderSizeField).clear().type('1');
|
||||
cy.getByTestId(orderPriceField).clear().type('1.123456');
|
||||
cy.getByTestId('dealticket-error-message-price-limit').should(
|
||||
'have.text',
|
||||
'Price accepts up to 5 decimal places'
|
||||
);
|
||||
});
|
||||
|
||||
describe('time in force validations', function () {
|
||||
const validTIF = TIFlist;
|
||||
validTIF.forEach((tif) => {
|
||||
// 7002-SORD-023
|
||||
// 7002-SORD-024
|
||||
// 7002-SORD-025
|
||||
// 7002-SORD-026
|
||||
// 7002-SORD-027
|
||||
// 7002-SORD-028
|
||||
|
||||
it(`must be able to select ${tif.code}`, function () {
|
||||
cy.getByTestId(orderTIFDropDown).select(tif.value);
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
tif.text
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('selections should be remembered', () => {
|
||||
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTT');
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
TIFlist.filter((item) => item.code === 'IOC')[0].text
|
||||
);
|
||||
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_FOK');
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
TIFlist.filter((item) => item.code === 'GTT')[0].text
|
||||
);
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
TIFlist.filter((item) => item.code === 'FOK')[0].text
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('market order validations', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('must not see the price unit', function () {
|
||||
// 7002-SORD-019
|
||||
cy.getByTestId(orderPriceField).should('not.exist');
|
||||
});
|
||||
|
||||
describe('time in force validations', function () {
|
||||
const validTIF = TIFlist.filter((tif) => ['FOK', 'IOC'].includes(tif.code));
|
||||
const invalidTIF = TIFlist.filter(
|
||||
(tif) => !['FOK', 'IOC'].includes(tif.code)
|
||||
);
|
||||
|
||||
validTIF.forEach((tif) => {
|
||||
// 7002-SORD-025
|
||||
// 7002-SORD-026
|
||||
|
||||
it(`must be able to select ${tif.code}`, function () {
|
||||
cy.getByTestId(orderTIFDropDown).select(tif.value);
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
tif.text
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
invalidTIF.forEach((tif) => {
|
||||
// 7002-SORD-023
|
||||
// 7002-SORD-024
|
||||
// 7002-SORD-027
|
||||
// 7002-SORD-028
|
||||
it(`must not be able to select ${tif.code}`, function () {
|
||||
cy.getByTestId(orderTIFDropDown).should('not.contain', tif.text);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('suspended market validation', { tags: '@regression' }, () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
@@ -0,0 +1,329 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { mockConnectWallet } from '@vegaprotocol/cypress';
|
||||
|
||||
const orderSizeField = 'order-size';
|
||||
const orderPriceField = 'order-price';
|
||||
const orderTIFDropDown = 'order-tif';
|
||||
const placeOrderBtn = 'place-order';
|
||||
const toggleShort = 'order-side-SIDE_SELL';
|
||||
const toggleLong = 'order-side-SIDE_BUY';
|
||||
const toggleLimit = 'order-type-TYPE_LIMIT';
|
||||
const toggleMarket = 'order-type-TYPE_MARKET';
|
||||
|
||||
const TIFlist = Object.values(Schema.OrderTimeInForce).map((value) => {
|
||||
return {
|
||||
code: Schema.OrderTimeInForceCode[value],
|
||||
value,
|
||||
text: Schema.OrderTimeInForceMapping[value],
|
||||
};
|
||||
});
|
||||
|
||||
describe('time in force default values', () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('must have market order set up to IOC by default', function () {
|
||||
// 7002-SORD-031
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
TIFlist.filter((item) => item.code === 'IOC')[0].text
|
||||
);
|
||||
});
|
||||
|
||||
it('must have time in force set to GTC for limit order', function () {
|
||||
// 7002-SORD-031
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
TIFlist.filter((item) => item.code === 'GTC')[0].text
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deal ticket validation', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('must show place order button and connect wallet if wallet is not connected', () => {
|
||||
// 0003-WTXN-001
|
||||
cy.getByTestId('connect-vega-wallet'); // Not connected
|
||||
cy.getByTestId('order-connect-wallet').should('exist');
|
||||
cy.getByTestId(placeOrderBtn).should('exist');
|
||||
cy.getByTestId('deal-ticket-connect-wallet').should('exist');
|
||||
});
|
||||
|
||||
it('must be able to select order direction - long/short', function () {
|
||||
// 7002-SORD-004
|
||||
cy.getByTestId(toggleShort).click().children('input').should('be.checked');
|
||||
cy.getByTestId(toggleLong).click().children('input').should('be.checked');
|
||||
});
|
||||
|
||||
it('must be able to select order type - limit/market', function () {
|
||||
// 7002-SORD-005
|
||||
// 7002-SORD-006
|
||||
// 7002-SORD-007
|
||||
cy.getByTestId(toggleLimit).click().children('input').should('be.checked');
|
||||
cy.getByTestId(toggleMarket).click().children('input').should('be.checked');
|
||||
});
|
||||
|
||||
it('order connect vega wallet button should connect', () => {
|
||||
mockConnectWallet();
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.getByTestId(orderPriceField).clear().type('101');
|
||||
cy.getByTestId('order-connect-wallet').click();
|
||||
cy.getByTestId('dialog-content').should('be.visible');
|
||||
cy.getByTestId('connectors-list')
|
||||
.find('[data-testid="connector-jsonRpc"]')
|
||||
.click();
|
||||
cy.wait('@walletReq');
|
||||
cy.getByTestId(placeOrderBtn).should('be.visible');
|
||||
cy.getByTestId(toggleLimit).children('input').should('be.checked');
|
||||
cy.getByTestId(orderPriceField).should('have.value', '101');
|
||||
});
|
||||
});
|
||||
|
||||
describe('deal ticket size validation', { tags: '@smoke' }, function () {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('must warn if order size input has too many digits after the decimal place', function () {
|
||||
// 7002-SORD-016
|
||||
cy.getByTestId('order-type-TYPE_MARKET').click();
|
||||
cy.getByTestId(orderSizeField).clear().type('1.234');
|
||||
cy.getByTestId(placeOrderBtn).should('not.be.disabled');
|
||||
cy.getByTestId(placeOrderBtn).click();
|
||||
cy.getByTestId(placeOrderBtn).should('be.disabled');
|
||||
cy.getByTestId('dealticket-error-message-size-market').should(
|
||||
'have.text',
|
||||
'Size must be whole numbers for this market'
|
||||
);
|
||||
});
|
||||
|
||||
it('must warn if order size is set to 0', function () {
|
||||
cy.getByTestId('order-type-TYPE_MARKET').click();
|
||||
cy.getByTestId(orderSizeField).clear().type('0');
|
||||
cy.getByTestId(placeOrderBtn).should('not.be.disabled');
|
||||
cy.getByTestId(placeOrderBtn).click();
|
||||
cy.getByTestId(placeOrderBtn).should('be.disabled');
|
||||
cy.getByTestId('dealticket-error-message-size-market').should(
|
||||
'have.text',
|
||||
'Size cannot be lower than 1'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('limit order validations', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('must see the price unit', function () {
|
||||
// 7002-SORD-018
|
||||
cy.getByTestId(orderPriceField)
|
||||
.siblings('label')
|
||||
.should('have.text', 'Price (DAI)');
|
||||
});
|
||||
|
||||
it('must see warning when placing an order with expiry date in past', () => {
|
||||
const expiresAt = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
||||
const expiresAtInputValue = expiresAt.toISOString().substring(0, 16);
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.getByTestId(orderPriceField).clear().type('0.1');
|
||||
cy.getByTestId(orderSizeField).clear().type('1');
|
||||
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTT');
|
||||
|
||||
cy.log('choosing yesterday');
|
||||
cy.getByTestId('date-picker-field').type(expiresAtInputValue);
|
||||
|
||||
cy.getByTestId(placeOrderBtn).click();
|
||||
|
||||
cy.getByTestId('dealticket-error-message-expiry').should(
|
||||
'have.text',
|
||||
'The expiry date that you have entered appears to be in the past'
|
||||
);
|
||||
});
|
||||
|
||||
it('must see warning if price has too many digits after decimal place', function () {
|
||||
// 7002-SORD-059
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTC');
|
||||
cy.getByTestId(orderSizeField).clear().type('1');
|
||||
cy.getByTestId(orderPriceField).clear().type('1.123456');
|
||||
cy.getByTestId('dealticket-error-message-price-limit').should(
|
||||
'have.text',
|
||||
'Price accepts up to 5 decimal places'
|
||||
);
|
||||
});
|
||||
|
||||
describe('time in force validations', function () {
|
||||
const validTIF = TIFlist;
|
||||
validTIF.forEach((tif) => {
|
||||
// 7002-SORD-023
|
||||
// 7002-SORD-024
|
||||
// 7002-SORD-025
|
||||
// 7002-SORD-026
|
||||
// 7002-SORD-027
|
||||
// 7002-SORD-028
|
||||
|
||||
it(`must be able to select ${tif.code}`, function () {
|
||||
cy.getByTestId(orderTIFDropDown).select(tif.value);
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
tif.text
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('selections should be remembered', () => {
|
||||
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTT');
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
TIFlist.filter((item) => item.code === 'IOC')[0].text
|
||||
);
|
||||
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_FOK');
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
TIFlist.filter((item) => item.code === 'GTT')[0].text
|
||||
);
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
TIFlist.filter((item) => item.code === 'FOK')[0].text
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('market order validations', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('must not see the price unit', function () {
|
||||
// 7002-SORD-019
|
||||
cy.getByTestId(orderPriceField).should('not.exist');
|
||||
});
|
||||
|
||||
describe('time in force validations', function () {
|
||||
const validTIF = TIFlist.filter((tif) => ['FOK', 'IOC'].includes(tif.code));
|
||||
const invalidTIF = TIFlist.filter(
|
||||
(tif) => !['FOK', 'IOC'].includes(tif.code)
|
||||
);
|
||||
|
||||
validTIF.forEach((tif) => {
|
||||
// 7002-SORD-025
|
||||
// 7002-SORD-026
|
||||
|
||||
it(`must be able to select ${tif.code}`, function () {
|
||||
cy.getByTestId(orderTIFDropDown).select(tif.value);
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
tif.text
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
invalidTIF.forEach((tif) => {
|
||||
// 7002-SORD-023
|
||||
// 7002-SORD-024
|
||||
// 7002-SORD-027
|
||||
// 7002-SORD-028
|
||||
it(`must not be able to select ${tif.code}`, function () {
|
||||
cy.getByTestId(orderTIFDropDown).should('not.contain', tif.text);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('post and reduce order validations', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
const validTIF = TIFlist.filter((tif) => ['FOK', 'IOC'].includes(tif.code));
|
||||
|
||||
validTIF.forEach((tif) => {
|
||||
// 7002-SORD-025
|
||||
// 7002-SORD-026
|
||||
|
||||
it(`post and reduce order market for ${tif.code}`, function () {
|
||||
cy.getByTestId(orderTIFDropDown).select(tif.value);
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
tif.text
|
||||
);
|
||||
cy.getByTestId('post-only').should('be.disabled');
|
||||
cy.getByTestId('reduce-only').should('be.enabled');
|
||||
});
|
||||
});
|
||||
|
||||
validTIF.forEach((tif) => {
|
||||
it(`post and reduce order limit for ${tif.code}`, function () {
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.getByTestId(orderTIFDropDown).select(tif.value);
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
tif.text
|
||||
);
|
||||
cy.getByTestId('post-only').should('be.disabled');
|
||||
cy.getByTestId('reduce-only').should('be.enabled');
|
||||
});
|
||||
});
|
||||
|
||||
const validTIFLimit = TIFlist.filter((tif) =>
|
||||
['GFA', 'GFN', 'GTC', 'GTT'].includes(tif.code)
|
||||
);
|
||||
|
||||
validTIFLimit.forEach((tif) => {
|
||||
it(`post and reduce order for limit ${tif.code}`, function () {
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.getByTestId(orderTIFDropDown).select(tif.value);
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
tif.text
|
||||
);
|
||||
cy.getByTestId('post-only').should('be.enabled');
|
||||
cy.getByTestId('reduce-only').should('be.disabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -35,6 +35,8 @@ type MarketPageMockData = {
|
||||
trigger?: Schema.AuctionTrigger;
|
||||
};
|
||||
|
||||
const ORACLE_PUBKEY = Cypress.env('ORACLE_PUBKEY');
|
||||
|
||||
const marketDataOverride = (
|
||||
data: MarketPageMockData
|
||||
): PartialDeep<MarketDataQuery> => ({
|
||||
@@ -96,7 +98,54 @@ const mockTradingPage = (
|
||||
aliasGQLQuery(req, 'Margins', marginsQuery());
|
||||
aliasGQLQuery(req, 'Assets', assetsQuery());
|
||||
aliasGQLQuery(req, 'Asset', assetQuery());
|
||||
aliasGQLQuery(req, 'MarketInfo', marketInfoQuery());
|
||||
aliasGQLQuery(
|
||||
req,
|
||||
'MarketInfo',
|
||||
marketInfoQuery({
|
||||
market: {
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
product: {
|
||||
dataSourceSpecForSettlementData: {
|
||||
data: {
|
||||
sourceType: {
|
||||
sourceType: {
|
||||
signers: [
|
||||
{
|
||||
__typename: 'Signer',
|
||||
signer: {
|
||||
__typename: 'PubKey',
|
||||
key: ORACLE_PUBKEY,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
data: {
|
||||
sourceType: {
|
||||
sourceType: {
|
||||
signers: [
|
||||
{
|
||||
__typename: 'Signer',
|
||||
signer: {
|
||||
__typename: 'PubKey',
|
||||
key: ORACLE_PUBKEY,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
aliasGQLQuery(req, 'Trades', tradesQuery());
|
||||
aliasGQLQuery(req, 'Chart', chartQuery());
|
||||
aliasGQLQuery(req, 'Candles', candlesQuery());
|
||||
@@ -127,6 +176,40 @@ export const addMockTradingPage = () => {
|
||||
cy.mockGQL((req) => {
|
||||
mockTradingPage(req, state, tradingMode, trigger);
|
||||
});
|
||||
|
||||
// Prevent request to github, return some dummy content
|
||||
cy.intercept(
|
||||
'GET',
|
||||
/^https:\/\/raw.githubusercontent.com\/vegaprotocol\/well-known/,
|
||||
{
|
||||
body: [
|
||||
{
|
||||
name: 'Another oracle',
|
||||
url: 'https://zombo.com',
|
||||
description_markdown:
|
||||
'Some markdown describing the oracle provider.\n\nTwitter: @FacesPics2\n',
|
||||
oracle: {
|
||||
status: 'GOOD',
|
||||
status_reason: '',
|
||||
first_verified: '2022-01-01T00:00:00.000Z',
|
||||
last_verified: '2022-12-31T00:00:00.000Z',
|
||||
type: 'public_key',
|
||||
public_key: ORACLE_PUBKEY,
|
||||
},
|
||||
proofs: [
|
||||
{
|
||||
format: 'signed_message',
|
||||
available: true,
|
||||
type: 'public_key',
|
||||
public_key: ORACLE_PUBKEY,
|
||||
message: 'SOMEHEX',
|
||||
},
|
||||
],
|
||||
github_link: `https://github.com/vegaprotocol/well-known/blob/main/oracle-providers/public_key-${ORACLE_PUBKEY}.toml`,
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
|
||||
NX_VEGA_ENV=STAGNET3
|
||||
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
|
||||
@@ -10,3 +11,4 @@ NX_VEGA_TOKEN_URL=https://token.fairground.wtf
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
||||
@@ -11,6 +11,7 @@ NX_VEGA_URL=http://localhost:3028/query
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
|
||||
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
|
||||
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
|
||||
@@ -10,4 +10,5 @@ NX_VEGA_TOKEN_URL=https://token.fairground.wtf
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
|
||||
@@ -9,4 +9,5 @@ NX_VEGA_TOKEN_URL=https://token.vega.xyz
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user