Compare commits
56
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9456249e18 | ||
|
|
d44a000055 | ||
|
|
1322af5ee2 | ||
|
|
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 |
@@ -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();
|
||||
|
||||
@@ -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')
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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"]';
|
||||
@@ -18,7 +19,6 @@ 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(
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -7,9 +7,10 @@ query PreviousEpoch($epochId: ID) {
|
||||
id
|
||||
rewardScore {
|
||||
rawValidatorScore
|
||||
performanceScore
|
||||
}
|
||||
rankingScore {
|
||||
performanceScore
|
||||
stakeScore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -81,9 +81,10 @@ const MOCK_PREVIOUS_EPOCH: PreviousEpochQuery = {
|
||||
id: 'ccc022b7e63a4d0a6d3a193c3940c88574060e58a184964c994998d86835a1b4',
|
||||
rewardScore: {
|
||||
rawValidatorScore: '0.25',
|
||||
performanceScore: '0.9998677767864936',
|
||||
},
|
||||
rankingScore: {
|
||||
performanceScore: '0.9998677767864936',
|
||||
stakeScore: '0.2499583402766206',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -92,9 +93,10 @@ const MOCK_PREVIOUS_EPOCH: PreviousEpochQuery = {
|
||||
id: '966438c6bffac737cfb08173ffcb3f393c4692b099ad80cb45a82e2dc0a8cf99',
|
||||
rewardScore: {
|
||||
rawValidatorScore: '0.3',
|
||||
performanceScore: '1',
|
||||
},
|
||||
rankingScore: {
|
||||
performanceScore: '1',
|
||||
stakeScore: '0.25',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -103,9 +105,10 @@ const MOCK_PREVIOUS_EPOCH: PreviousEpochQuery = {
|
||||
id: '12c81b738e8051152e1afe44376ec37bca9216466e6d44cdd772194bad0ada81',
|
||||
rewardScore: {
|
||||
rawValidatorScore: '0.35',
|
||||
performanceScore: '0.999629748500531',
|
||||
},
|
||||
rankingScore: {
|
||||
performanceScore: '0.999629748500531',
|
||||
stakeScore: '0.2312',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
+16
-20
@@ -10,7 +10,6 @@ import {
|
||||
getFormattedPerformanceScore,
|
||||
getLastEpochScoreAndPerformance,
|
||||
getNormalisedVotingPower,
|
||||
getOverstakedAmount,
|
||||
getOverstakingPenalty,
|
||||
getPerformancePenalty,
|
||||
getTotalPenalties,
|
||||
@@ -52,7 +51,6 @@ 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;
|
||||
@@ -164,14 +162,11 @@ export const ConsensusValidatorsTable = ({
|
||||
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,
|
||||
@@ -184,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),
|
||||
@@ -194,18 +189,19 @@ 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
|
||||
),
|
||||
|
||||
+19
-19
@@ -7,7 +7,6 @@ import { BigNumber } from '../../../../lib/bignumber';
|
||||
import {
|
||||
getFormattedPerformanceScore,
|
||||
getLastEpochScoreAndPerformance,
|
||||
getOverstakedAmount,
|
||||
getOverstakingPenalty,
|
||||
getPerformancePenalty,
|
||||
getTotalPenalties,
|
||||
@@ -82,21 +81,21 @@ export const StandbyPendingValidatorsTable = ({
|
||||
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)
|
||||
@@ -142,18 +141,19 @@ 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
|
||||
),
|
||||
|
||||
@@ -20,7 +20,6 @@ import { SubHeading } from '../../../components/heading';
|
||||
import {
|
||||
getLastEpochScoreAndPerformance,
|
||||
getNormalisedVotingPower,
|
||||
getOverstakedAmount,
|
||||
getOverstakingPenalty,
|
||||
getPerformancePenalty,
|
||||
getTotalPenalties,
|
||||
@@ -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(
|
||||
@@ -245,7 +238,7 @@ export const ValidatorTable = ({
|
||||
|
||||
<Tooltip description={t('OverstakedPenaltyDescription')}>
|
||||
<span data-testid="overstaking-penalty">
|
||||
{getOverstakingPenalty(overstakedAmount, node.stakedTotal)}
|
||||
{getOverstakingPenalty(rawValidatorScore, stakeScore)}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</KeyValueTableRow>
|
||||
|
||||
@@ -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%');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -84,6 +84,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 +100,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 +116,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 +132,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 +151,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 +160,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 +194,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 +210,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 +226,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 +271,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 +287,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 +305,8 @@ describe(
|
||||
size: '100',
|
||||
price: '1.00',
|
||||
expiresAt: displayTomorrow(),
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
};
|
||||
createOrder(order);
|
||||
testOrderSubmission(order, {
|
||||
@@ -320,6 +346,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 +363,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 +380,8 @@ describe(
|
||||
size: '100',
|
||||
price: '1.00',
|
||||
expiresAt: displayTomorrow(),
|
||||
postOnly: false,
|
||||
reduceOnly: false,
|
||||
};
|
||||
createOrder(order);
|
||||
testOrderSubmission(order, {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,4 +10,5 @@ NX_VEGA_TOKEN_URL=https://stagnet1.token.vega.xyz
|
||||
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_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
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
|
||||
@@ -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_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
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
|
||||
@@ -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/releases
|
||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
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
|
||||
@@ -10,4 +10,5 @@ NX_VEGA_TOKEN_URL=https://validator-testnet.governance.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_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
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
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
matchFilter,
|
||||
liquidityProvisionsDataProvider,
|
||||
LiquidityTable,
|
||||
lpAggregatedDataProvider,
|
||||
@@ -16,7 +17,6 @@ import {
|
||||
useNetworkParams,
|
||||
updateGridData,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
AsyncRenderer,
|
||||
Tab,
|
||||
@@ -25,19 +25,25 @@ import {
|
||||
Indicator,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { Header, HeaderStat, HeaderTitle } from '../../components/header';
|
||||
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { IGetRowsParams } from 'ag-grid-community';
|
||||
|
||||
import type { LiquidityProvisionData } from '@vegaprotocol/liquidity';
|
||||
import type { LiquidityProvisionData, Filter } from '@vegaprotocol/liquidity';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
|
||||
import { useMarket, useStaticMarketData } from '@vegaprotocol/market-list';
|
||||
|
||||
const enum LiquidityTabs {
|
||||
Active = 'active',
|
||||
Inactive = 'inactive',
|
||||
MyLiquidityProvision = 'myLP',
|
||||
}
|
||||
|
||||
export const Liquidity = () => {
|
||||
const params = useParams();
|
||||
const marketId = params.marketId;
|
||||
@@ -48,18 +54,21 @@ const useReloadLiquidityData = (marketId: string | undefined) => {
|
||||
const { reload } = useDataProvider({
|
||||
dataProvider: liquidityProvisionsDataProvider,
|
||||
variables: { marketId: marketId || '' },
|
||||
update: () => true,
|
||||
skip: !marketId,
|
||||
});
|
||||
useEffect(() => {
|
||||
const interval = setInterval(reload, 10000);
|
||||
const interval = setInterval(reload, 30000);
|
||||
return () => clearInterval(interval);
|
||||
}, [reload]);
|
||||
};
|
||||
|
||||
export const LiquidityContainer = ({
|
||||
marketId,
|
||||
filter,
|
||||
}: {
|
||||
marketId: string | undefined;
|
||||
filter?: Filter;
|
||||
}) => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const { data: market } = useMarket(marketId);
|
||||
@@ -78,7 +87,7 @@ export const LiquidityContainer = ({
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: lpAggregatedDataProvider,
|
||||
update,
|
||||
variables: { marketId: marketId || '' },
|
||||
variables: { marketId: marketId || '', filter },
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
@@ -126,47 +135,9 @@ export const LiquidityContainer = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const LiquidityViewContainer = ({
|
||||
marketId,
|
||||
}: {
|
||||
marketId: string | undefined;
|
||||
}) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const LiquidityViewHeader = memo(({ marketId }: { marketId?: string }) => {
|
||||
const { data: market } = useMarket(marketId);
|
||||
const { data: marketData } = useStaticMarketData(marketId);
|
||||
|
||||
const dataRef = useRef<LiquidityProvisionData[] | null>(null);
|
||||
|
||||
// To be removed when liquidityProvision subscriptions are working
|
||||
useReloadLiquidityData(marketId);
|
||||
|
||||
const update = useCallback(
|
||||
({ data }: { data: LiquidityProvisionData[] | null }) => {
|
||||
if (!gridRef.current?.api) {
|
||||
return false;
|
||||
}
|
||||
if (dataRef.current?.length) {
|
||||
dataRef.current = data;
|
||||
gridRef.current.api.refreshInfiniteCache();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
[gridRef]
|
||||
);
|
||||
|
||||
const {
|
||||
data: liquidityProviders,
|
||||
loading,
|
||||
error,
|
||||
} = useDataProvider({
|
||||
dataProvider: lpAggregatedDataProvider,
|
||||
update,
|
||||
variables: { marketId: marketId || '' },
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
const targetStake = marketData?.targetStake;
|
||||
const suppliedStake = marketData?.suppliedStake;
|
||||
const assetDecimalPlaces =
|
||||
@@ -178,44 +149,8 @@ export const LiquidityViewContainer = ({
|
||||
NetworkParams.market_liquidity_stakeToCcyVolume,
|
||||
NetworkParams.market_liquidity_targetstake_triggering_ratio,
|
||||
]);
|
||||
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
|
||||
const triggeringRatio =
|
||||
params.market_liquidity_targetstake_triggering_ratio || '1';
|
||||
const myLpEdges = useMemo(
|
||||
() => liquidityProviders?.filter((e) => e.party.id === pubKey),
|
||||
[liquidityProviders, pubKey]
|
||||
);
|
||||
const activeEdges = useMemo(
|
||||
() =>
|
||||
liquidityProviders?.filter(
|
||||
(e) => e.status === Schema.LiquidityProvisionStatus.STATUS_ACTIVE
|
||||
),
|
||||
[liquidityProviders]
|
||||
);
|
||||
const inactiveEdges = useMemo(
|
||||
() =>
|
||||
liquidityProviders?.filter(
|
||||
(e) => e.status !== Schema.LiquidityProvisionStatus.STATUS_ACTIVE
|
||||
),
|
||||
[liquidityProviders]
|
||||
);
|
||||
|
||||
const enum LiquidityTabs {
|
||||
Active = 'active',
|
||||
Inactive = 'inactive',
|
||||
MyLiquidityProvision = 'myLP',
|
||||
}
|
||||
|
||||
const getActiveDefaultId = () => {
|
||||
if (myLpEdges && myLpEdges.length > 0) {
|
||||
return LiquidityTabs.MyLiquidityProvision;
|
||||
}
|
||||
if (activeEdges?.length) return LiquidityTabs.Active;
|
||||
else if (inactiveEdges && inactiveEdges.length > 0) {
|
||||
return LiquidityTabs.Inactive;
|
||||
}
|
||||
return LiquidityTabs.Active;
|
||||
};
|
||||
|
||||
const { percentage, status } = useCheckLiquidityStatus({
|
||||
suppliedStake: suppliedStake || 0,
|
||||
@@ -224,106 +159,113 @@ export const LiquidityViewContainer = ({
|
||||
});
|
||||
|
||||
return (
|
||||
<AsyncRenderer loading={loading} error={error} data={liquidityProviders}>
|
||||
<div className="h-full grid grid-rows-[min-content_1fr]">
|
||||
<Header
|
||||
title={
|
||||
market?.tradableInstrument.instrument.name &&
|
||||
market?.tradableInstrument.instrument.code &&
|
||||
marketId && (
|
||||
<HeaderTitle
|
||||
primaryContent={`${
|
||||
market.tradableInstrument.instrument.code
|
||||
} ${t('liquidity provision')}`}
|
||||
secondaryContent={
|
||||
<Link to={Links[Routes.MARKET](marketId)}>
|
||||
<UiToolkitLink>{t('Go to trading')}</UiToolkitLink>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
<HeaderStat
|
||||
heading={t('Target stake')}
|
||||
description={tooltipMapping['targetStake']}
|
||||
>
|
||||
<div>
|
||||
{targetStake
|
||||
? `${addDecimalsFormatNumber(
|
||||
targetStake,
|
||||
assetDecimalPlaces ?? 0
|
||||
)} ${symbol}`
|
||||
: '-'}
|
||||
</div>
|
||||
</HeaderStat>
|
||||
<HeaderStat
|
||||
heading={t('Supplied stake')}
|
||||
description={tooltipMapping['suppliedStake']}
|
||||
>
|
||||
<div>
|
||||
{suppliedStake
|
||||
? `${addDecimalsFormatNumber(
|
||||
suppliedStake,
|
||||
assetDecimalPlaces ?? 0
|
||||
)} ${symbol}`
|
||||
: '-'}
|
||||
</div>
|
||||
</HeaderStat>
|
||||
<HeaderStat
|
||||
heading={t('Liquidity supplied')}
|
||||
testId="liquidity-supplied"
|
||||
>
|
||||
<Indicator variant={status} />
|
||||
<Header
|
||||
title={
|
||||
market?.tradableInstrument.instrument.name &&
|
||||
market?.tradableInstrument.instrument.code &&
|
||||
marketId && (
|
||||
<HeaderTitle
|
||||
primaryContent={`${market.tradableInstrument.instrument.code} ${t(
|
||||
'liquidity provision'
|
||||
)}`}
|
||||
secondaryContent={
|
||||
<Link to={Links[Routes.MARKET](marketId)}>
|
||||
<UiToolkitLink>{t('Go to trading')}</UiToolkitLink>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
<HeaderStat
|
||||
heading={t('Target stake')}
|
||||
description={tooltipMapping['targetStake']}
|
||||
>
|
||||
<div>
|
||||
{targetStake
|
||||
? `${addDecimalsFormatNumber(
|
||||
targetStake,
|
||||
assetDecimalPlaces ?? 0
|
||||
)} ${symbol}`
|
||||
: '-'}
|
||||
</div>
|
||||
</HeaderStat>
|
||||
<HeaderStat
|
||||
heading={t('Supplied stake')}
|
||||
description={tooltipMapping['suppliedStake']}
|
||||
>
|
||||
<div>
|
||||
{suppliedStake
|
||||
? `${addDecimalsFormatNumber(
|
||||
suppliedStake,
|
||||
assetDecimalPlaces ?? 0
|
||||
)} ${symbol}`
|
||||
: '-'}
|
||||
</div>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Liquidity supplied')} testId="liquidity-supplied">
|
||||
<Indicator variant={status} />
|
||||
|
||||
{formatNumberPercentage(percentage, 2)}
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Market ID')}>
|
||||
<div className="break-word">{marketId}</div>
|
||||
</HeaderStat>
|
||||
</Header>
|
||||
<Tabs defaultValue={getActiveDefaultId()}>
|
||||
<Tab
|
||||
id={LiquidityTabs.MyLiquidityProvision}
|
||||
name={t('My liquidity provision')}
|
||||
hidden={!pubKey}
|
||||
>
|
||||
{myLpEdges && (
|
||||
<LiquidityTable
|
||||
ref={gridRef}
|
||||
rowData={myLpEdges}
|
||||
symbol={symbol}
|
||||
stakeToCcyVolume={stakeToCcyVolume}
|
||||
assetDecimalPlaces={assetDecimalPlaces}
|
||||
/>
|
||||
)}
|
||||
</Tab>
|
||||
<Tab id={LiquidityTabs.Active} name={t('Active')}>
|
||||
{activeEdges && (
|
||||
<LiquidityTable
|
||||
ref={gridRef}
|
||||
rowData={activeEdges}
|
||||
symbol={symbol}
|
||||
assetDecimalPlaces={assetDecimalPlaces}
|
||||
stakeToCcyVolume={stakeToCcyVolume}
|
||||
/>
|
||||
)}
|
||||
</Tab>
|
||||
{
|
||||
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
|
||||
{inactiveEdges && (
|
||||
<LiquidityTable
|
||||
ref={gridRef}
|
||||
rowData={inactiveEdges}
|
||||
symbol={symbol}
|
||||
assetDecimalPlaces={assetDecimalPlaces}
|
||||
stakeToCcyVolume={stakeToCcyVolume}
|
||||
/>
|
||||
)}
|
||||
</Tab>
|
||||
}
|
||||
</Tabs>
|
||||
</div>
|
||||
</AsyncRenderer>
|
||||
{formatNumberPercentage(percentage, 2)}
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Market ID')}>
|
||||
<div className="break-word">{marketId}</div>
|
||||
</HeaderStat>
|
||||
</Header>
|
||||
);
|
||||
});
|
||||
LiquidityViewHeader.displayName = 'LiquidityViewHeader';
|
||||
|
||||
export const LiquidityViewContainer = ({
|
||||
marketId,
|
||||
}: {
|
||||
marketId: string | undefined;
|
||||
}) => {
|
||||
const [tab, setTab] = useState<string | undefined>(undefined);
|
||||
const { pubKey } = useVegaWallet();
|
||||
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: lpAggregatedDataProvider,
|
||||
skipUpdates: true,
|
||||
variables: { marketId: marketId || '' },
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
if (pubKey && data.some((lp) => matchFilter({ partyId: pubKey }, lp))) {
|
||||
setTab(LiquidityTabs.MyLiquidityProvision);
|
||||
return;
|
||||
}
|
||||
if (data.some((lp) => matchFilter({ active: true }, lp))) {
|
||||
setTab(LiquidityTabs.Active);
|
||||
return;
|
||||
}
|
||||
setTab(LiquidityTabs.Inactive);
|
||||
}
|
||||
}, [data, pubKey]);
|
||||
|
||||
return (
|
||||
<div className="h-full grid grid-rows-[min-content_1fr]">
|
||||
<LiquidityViewHeader marketId={marketId} />
|
||||
<Tabs value={tab || LiquidityTabs.Active} onValueChange={setTab}>
|
||||
<Tab
|
||||
id={LiquidityTabs.MyLiquidityProvision}
|
||||
name={t('My liquidity provision')}
|
||||
hidden={!pubKey}
|
||||
>
|
||||
<LiquidityContainer
|
||||
marketId={marketId}
|
||||
filter={{ partyId: pubKey || undefined }}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab id={LiquidityTabs.Active} name={t('Active')}>
|
||||
<LiquidityContainer marketId={marketId} filter={{ active: true }} />
|
||||
</Tab>
|
||||
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
|
||||
<LiquidityContainer marketId={marketId} filter={{ active: false }} />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { addDecimalsFormatNumber, titlefy } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
@@ -13,6 +13,7 @@ import { useGlobalStore, usePageTitleStore } from '../../stores';
|
||||
import { TradeGrid, TradePanels } from './trade-grid';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
|
||||
const calculatePrice = (markPrice?: string, decimalPlaces?: number) => {
|
||||
return markPrice && decimalPlaces
|
||||
@@ -66,14 +67,7 @@ export const MarketPage = () => {
|
||||
const update = useGlobalStore((store) => store.update);
|
||||
const lastMarketId = useGlobalStore((store) => store.marketId);
|
||||
|
||||
const onSelect = useCallback(
|
||||
(id: string) => {
|
||||
if (id && id !== marketId) {
|
||||
navigate(Links[Routes.MARKET](id));
|
||||
}
|
||||
},
|
||||
[marketId, navigate]
|
||||
);
|
||||
const onSelect = useMarketClickHandler();
|
||||
|
||||
const { data, error, loading } = useDataProvider({
|
||||
dataProvider: marketProvider,
|
||||
|
||||
@@ -8,7 +8,7 @@ import { TradesContainer } from '@vegaprotocol/trades';
|
||||
import { LayoutPriority } from 'allotment';
|
||||
import classNames from 'classnames';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import { memo, useCallback, useState } from 'react';
|
||||
import { memo, useState } from 'react';
|
||||
import type { ReactNode, ComponentProps } from 'react';
|
||||
import { DepthChartContainer } from '@vegaprotocol/market-depth';
|
||||
import { CandlesChartContainer } from '@vegaprotocol/candles-chart';
|
||||
@@ -27,9 +27,9 @@ import { TradeMarketHeader } from './trade-market-header';
|
||||
import { NO_MARKET } from './constants';
|
||||
import { LiquidityContainer } from '../liquidity/liquidity';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import type { PinnedAsset } from '@vegaprotocol/accounts';
|
||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
|
||||
type MarketDependantView =
|
||||
| typeof CandlesChartContainer
|
||||
@@ -66,7 +66,7 @@ type TradingView = keyof typeof TradingViews;
|
||||
|
||||
interface TradeGridProps {
|
||||
market: Market | null;
|
||||
onSelect: (marketId: string) => void;
|
||||
onSelect: (marketId: string, metaKey?: boolean) => void;
|
||||
pinnedAsset?: PinnedAsset;
|
||||
}
|
||||
|
||||
@@ -78,15 +78,7 @@ interface BottomPanelProps {
|
||||
const MarketBottomPanel = memo(
|
||||
({ marketId, pinnedAsset }: BottomPanelProps) => {
|
||||
const { screenSize } = useScreenDimensions();
|
||||
const navigate = useNavigate();
|
||||
const onMarketClick = useCallback(
|
||||
(marketId: string) => {
|
||||
navigate(Links[Routes.MARKET](marketId), {
|
||||
replace: true,
|
||||
});
|
||||
},
|
||||
[navigate]
|
||||
);
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
|
||||
return 'xxxl' === screenSize ? (
|
||||
<ResizableGrid proportionalLayout minSize={200}>
|
||||
@@ -189,7 +181,7 @@ const MainGrid = memo(
|
||||
pinnedAsset,
|
||||
}: {
|
||||
marketId: string;
|
||||
onSelect?: (marketId: string) => void;
|
||||
onSelect: (marketId: string, metaKey?: boolean) => void;
|
||||
pinnedAsset?: PinnedAsset;
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
@@ -230,12 +222,7 @@ const MainGrid = memo(
|
||||
/>
|
||||
</Tab>
|
||||
<Tab id="info" name={t('Info')}>
|
||||
<TradingViews.Info
|
||||
marketId={marketId}
|
||||
onSelect={(id: string) => {
|
||||
onSelect?.(id);
|
||||
}}
|
||||
/>
|
||||
<TradingViews.Info marketId={marketId} />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</TradeGridChild>
|
||||
@@ -304,7 +291,7 @@ const TradeGridChild = ({ children }: TradeGridChildProps) => {
|
||||
|
||||
interface TradePanelsProps {
|
||||
market: Market | null;
|
||||
onSelect: (marketId: string) => void;
|
||||
onSelect: (marketId: string, metaKey?: boolean) => void;
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
onClickCollateral: () => void;
|
||||
pinnedAsset?: PinnedAsset;
|
||||
@@ -320,7 +307,7 @@ export const TradePanels = ({
|
||||
const renderView = () => {
|
||||
const Component = memo<{
|
||||
marketId: string;
|
||||
onSelect: (marketId: string) => void;
|
||||
onSelect: (marketId: string, metaKey?: boolean) => void;
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
onClickCollateral: () => void;
|
||||
pinnedAsset?: PinnedAsset;
|
||||
|
||||
@@ -22,7 +22,7 @@ import { MarketState as State } from '@vegaprotocol/types';
|
||||
|
||||
interface TradeMarketHeaderProps {
|
||||
market: Market | null;
|
||||
onSelect: (marketId: string) => void;
|
||||
onSelect: (marketId: string, metaKey?: boolean) => void;
|
||||
}
|
||||
|
||||
export const TradeMarketHeader = ({
|
||||
@@ -91,7 +91,6 @@ export const TradeMarketHeader = ({
|
||||
</HeaderStat>
|
||||
<HeaderStatMarketTradingMode
|
||||
marketId={market?.id}
|
||||
onSelect={onSelect}
|
||||
initialTradingMode={market?.tradingMode}
|
||||
/>
|
||||
<MarketState market={market} />
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
import { useCallback } from 'react';
|
||||
import { MarketsContainer } from '@vegaprotocol/market-list';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
|
||||
export const Markets = () => {
|
||||
const navigate = useNavigate();
|
||||
const handleOnSelect = useCallback(
|
||||
(marketId: string) => {
|
||||
navigate(Links[Routes.MARKET](marketId));
|
||||
},
|
||||
[navigate]
|
||||
);
|
||||
|
||||
const handleOnSelect = useMarketClickHandler();
|
||||
return <MarketsContainer onSelect={handleOnSelect} />;
|
||||
};
|
||||
|
||||
@@ -19,25 +19,18 @@ import { usePageTitleStore } from '../../stores';
|
||||
import { LedgerContainer } from '@vegaprotocol/ledger';
|
||||
import { AccountsContainer } from '../../components/accounts-container';
|
||||
import { AccountHistoryContainer } from './account-history-container';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
|
||||
export const Portfolio = () => {
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy([t('Portfolio')]));
|
||||
}, [updateTitle]);
|
||||
|
||||
const onMarketClick = (marketId: string) => {
|
||||
navigate(Links[Routes.MARKET](marketId), {
|
||||
replace: true,
|
||||
});
|
||||
};
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
|
||||
const wrapperClasses = 'h-full max-h-full flex flex-col';
|
||||
return (
|
||||
|
||||
@@ -1,39 +1,16 @@
|
||||
import {
|
||||
AnnouncementBanner,
|
||||
ExternalLink,
|
||||
Icon,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
import React from 'react';
|
||||
import { AnnouncementBanner } from '@vegaprotocol/announcements';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
|
||||
export const Banner = () => {
|
||||
const { update, shouldDisplayAnnouncementBanner } = useGlobalStore(
|
||||
(store) => ({
|
||||
update: store.update,
|
||||
shouldDisplayAnnouncementBanner: store.shouldDisplayAnnouncementBanner,
|
||||
})
|
||||
);
|
||||
const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
|
||||
|
||||
// Return an empty div so that the grid layout in _app.page.ts
|
||||
// renders correctly
|
||||
if (!shouldDisplayAnnouncementBanner) {
|
||||
if (!ANNOUNCEMENTS_CONFIG_URL) {
|
||||
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={() => update({ shouldDisplayAnnouncementBanner: 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>
|
||||
<AnnouncementBanner app="console" configUrl={ANNOUNCEMENTS_CONFIG_URL} />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@ const getTradingModeLabel = (
|
||||
|
||||
interface HeaderStatMarketTradingModeProps {
|
||||
marketId?: string;
|
||||
onSelect?: (marketId: string) => void;
|
||||
onSelect?: (marketId: string, metaKey?: boolean) => void;
|
||||
initialTradingMode?: Schema.MarketTradingMode;
|
||||
initialTrigger?: Schema.AuctionTrigger;
|
||||
}
|
||||
@@ -66,7 +66,9 @@ export const MarketTradingMode = ({
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
description={<TradingModeTooltip marketId={marketId} skip={!inView} />}
|
||||
description={
|
||||
<TradingModeTooltip marketId={marketId} skip={!inView} skipGrid />
|
||||
}
|
||||
>
|
||||
<span ref={ref}>
|
||||
{getTradingModeLabel(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { RefObject } from 'react';
|
||||
import type { RefObject, MouseEvent } from 'react';
|
||||
import { FeesCell } from '@vegaprotocol/market-info';
|
||||
import {
|
||||
calcCandleHigh,
|
||||
@@ -157,14 +157,14 @@ export const columnHeaders: Column[] = [
|
||||
];
|
||||
|
||||
export type OnCellClickHandler = (
|
||||
e: React.MouseEvent,
|
||||
e: MouseEvent,
|
||||
kind: ColumnKind,
|
||||
value: string
|
||||
) => void;
|
||||
|
||||
export const columns = (
|
||||
market: MarketMaybeWithDataAndCandles,
|
||||
onSelect: (id: string) => void,
|
||||
onSelect: (id: string, metaKey?: boolean) => void,
|
||||
onCellClick: OnCellClickHandler,
|
||||
inViewRoot?: RefObject<HTMLElement>
|
||||
) => {
|
||||
@@ -174,14 +174,7 @@ export const columns = (
|
||||
const candleLow = market.candles && calcCandleLow(market.candles);
|
||||
const candleHigh = market.candles && calcCandleHigh(market.candles);
|
||||
const candleVolume = market.candles && calcCandleVolume(market.candles);
|
||||
const handleKeyPress = (
|
||||
event: React.KeyboardEvent<HTMLAnchorElement>,
|
||||
id: string
|
||||
) => {
|
||||
if (event.key === 'Enter' && onSelect) {
|
||||
return onSelect(id);
|
||||
}
|
||||
};
|
||||
|
||||
const selectMarketColumns: Column[] = [
|
||||
{
|
||||
kind: ColumnKind.Market,
|
||||
@@ -189,10 +182,10 @@ export const columns = (
|
||||
<Link
|
||||
to={Links[Routes.MARKET](market.id)}
|
||||
data-testid={`market-link-${market.id}`}
|
||||
onKeyPress={(event) => handleKeyPress(event, market.id)}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
onSelect(market.id);
|
||||
e.stopPropagation();
|
||||
onSelect(market.id, e.metaKey);
|
||||
}}
|
||||
>
|
||||
<UILink>{market.tradableInstrument.instrument.code}</UILink>
|
||||
@@ -352,7 +345,7 @@ export const columns = (
|
||||
|
||||
export const columnsPositionMarkets = (
|
||||
market: MarketMaybeWithDataAndCandles,
|
||||
onSelect: (id: string) => void,
|
||||
onSelect: (id: string, metaKey?: boolean) => void,
|
||||
inViewRoot?: RefObject<HTMLElement>,
|
||||
openVolume?: string,
|
||||
onCellClick?: OnCellClickHandler
|
||||
@@ -362,14 +355,6 @@ export const columnsPositionMarkets = (
|
||||
.filter((c: string | undefined): c is CandleClose => !isNil(c));
|
||||
const candleLow = market.candles && calcCandleLow(market.candles);
|
||||
const candleHigh = market.candles && calcCandleHigh(market.candles);
|
||||
const handleKeyPress = (
|
||||
event: React.KeyboardEvent<HTMLSpanElement>,
|
||||
id: string
|
||||
) => {
|
||||
if (event.key === 'Enter' && onSelect) {
|
||||
return onSelect(id);
|
||||
}
|
||||
};
|
||||
const candleVolume = market.candles && calcCandleVolume(market.candles);
|
||||
const selectMarketColumns: Column[] = [
|
||||
{
|
||||
@@ -378,10 +363,10 @@ export const columnsPositionMarkets = (
|
||||
<Link
|
||||
to={Links[Routes.MARKET](market.id)}
|
||||
data-testid={`market-link-${market.id}`}
|
||||
onKeyPress={(event) => handleKeyPress(event, market.id)}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
onSelect(market.id);
|
||||
e.stopPropagation();
|
||||
onSelect(market.id, e.metaKey);
|
||||
}}
|
||||
>
|
||||
<UILink>{market.tradableInstrument.instrument.code}</UILink>
|
||||
|
||||
@@ -37,14 +37,14 @@ export const SelectMarketTableRow = ({
|
||||
}: {
|
||||
detailed?: boolean;
|
||||
columns: Column[];
|
||||
onSelect: (id: string) => void;
|
||||
onSelect: (id: string, metaKey?: boolean) => void;
|
||||
marketId: string;
|
||||
}) => {
|
||||
return (
|
||||
<tr
|
||||
className={`hover:bg-neutral-200 dark:hover:bg-neutral-700 cursor-pointer relative h-[34px]`}
|
||||
onClick={() => {
|
||||
onSelect(marketId);
|
||||
onClick={(ev) => {
|
||||
onSelect(marketId, ev.metaKey);
|
||||
}}
|
||||
data-testid={`market-link-${marketId}`}
|
||||
>
|
||||
|
||||
@@ -178,6 +178,6 @@ describe('SelectMarket', () => {
|
||||
expect(screen.getByText('25.00%')).toBeTruthy(); // price change
|
||||
expect(container).toHaveTextContent(/1,000/); // volume
|
||||
fireEvent.click(screen.getAllByTestId(`market-link-1`)[0]);
|
||||
expect(onSelect).toHaveBeenCalledWith('1');
|
||||
expect(onSelect).toHaveBeenCalledWith('1', false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,7 +40,7 @@ export const SelectAllMarketsTableBody = ({
|
||||
markets?: MarketMaybeWithDataAndCandles[] | null;
|
||||
positions?: PositionFieldsFragment[];
|
||||
title?: string;
|
||||
onSelect: (id: string) => void;
|
||||
onSelect: (id: string, metaKey?: boolean) => void;
|
||||
onCellClick: OnCellClickHandler;
|
||||
headers?: Column[];
|
||||
tableColumns?: (
|
||||
@@ -95,7 +95,7 @@ export const SelectMarketPopover = ({
|
||||
}: {
|
||||
marketCode: string;
|
||||
marketName: string;
|
||||
onSelect: (id: string) => void;
|
||||
onSelect: (id: string, metaKey?: boolean) => void;
|
||||
onCellClick: OnCellClickHandler;
|
||||
}) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
@@ -116,8 +116,8 @@ export const SelectMarketPopover = ({
|
||||
skip: !pubKey,
|
||||
});
|
||||
const onSelectMarket = useCallback(
|
||||
(marketId: string) => {
|
||||
onSelect(marketId);
|
||||
(marketId: string, metaKey?: boolean) => {
|
||||
onSelect(marketId, metaKey);
|
||||
setOpen(false);
|
||||
},
|
||||
[onSelect]
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { useNavigate, useParams, useLocation } from 'react-router-dom';
|
||||
import { useCallback } from 'react';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
|
||||
export const useMarketClickHandler = (replace = false) => {
|
||||
const navigate = useNavigate();
|
||||
const { marketId } = useParams();
|
||||
const { pathname } = useLocation();
|
||||
const isMarketPage = pathname.match(/^\/markets\/(.+)/);
|
||||
return useCallback(
|
||||
(selectedId: string, metaKey?: boolean) => {
|
||||
const link = Links[Routes.MARKET](selectedId);
|
||||
if (metaKey) {
|
||||
window.open(`/#${link}`, '_blank');
|
||||
} else if (selectedId !== marketId || !isMarketPage) {
|
||||
navigate(link, { replace });
|
||||
}
|
||||
},
|
||||
[navigate, marketId, replace, isMarketPage]
|
||||
);
|
||||
};
|
||||
@@ -474,15 +474,20 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
}
|
||||
|
||||
if (tx.order && tx.order.rejectionReason) {
|
||||
const rejectionReason =
|
||||
getRejectionReason(tx.order) || tx.order.rejectionReason || '';
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>{t('Order rejected')}</ToastHeading>
|
||||
<p>
|
||||
{t(
|
||||
'Your order has been rejected because: %s',
|
||||
getRejectionReason(tx.order) || ''
|
||||
)}
|
||||
</p>
|
||||
{rejectionReason || tx.order.rejectionReason ? (
|
||||
<p>
|
||||
{t('Your order has been rejected because: %s', [
|
||||
rejectionReason || tx.order.rejectionReason,
|
||||
])}
|
||||
</p>
|
||||
) : (
|
||||
<p>{t('Your order has been rejected.')}</p>
|
||||
)}
|
||||
{tx.txHash && (
|
||||
<p className="break-all">
|
||||
<ExternalLink
|
||||
@@ -576,10 +581,9 @@ const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
walletNoConnectionCodes.includes(tx.error.code);
|
||||
if (orderRejection) {
|
||||
label = t('Order rejected');
|
||||
errorMessage = t(
|
||||
'Your order has been rejected because: %s',
|
||||
orderRejection
|
||||
);
|
||||
errorMessage = t('Your order has been rejected because: %s', [
|
||||
orderRejection || tx.order?.rejectionReason || ' ',
|
||||
]);
|
||||
}
|
||||
if (walletError) {
|
||||
label = t('Wallet disconnected');
|
||||
@@ -645,7 +649,11 @@ export const useVegaTransactionToasts = () => {
|
||||
|
||||
// Transaction can be successful but the order can be rejected by the network
|
||||
const intent =
|
||||
tx.order && [OrderStatus.STATUS_REJECTED].includes(tx.order.status)
|
||||
(tx.order &&
|
||||
[OrderStatus.STATUS_REJECTED, OrderStatus.STATUS_STOPPED].includes(
|
||||
tx.order.status
|
||||
)) ||
|
||||
tx.order?.rejectionReason
|
||||
? Intent.Danger
|
||||
: intentMap[tx.status];
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Head from 'next/head';
|
||||
import type { AppProps } from 'next/app';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
@@ -23,14 +25,12 @@ import {
|
||||
import './styles.css';
|
||||
import { useGlobalStore, usePageTitleStore } from '../stores';
|
||||
import { Footer } from '../components/footer';
|
||||
import { useMemo, useState } from 'react';
|
||||
import DialogsContainer from './dialogs-container';
|
||||
import ToastsManager from './toasts-manager';
|
||||
import { HashRouter, useLocation, useSearchParams } from 'react-router-dom';
|
||||
import { Connectors } from '../lib/vega-connectors';
|
||||
import { ViewingBanner } from '../components/viewing-banner';
|
||||
import { Banner } from '../components/banner';
|
||||
import classNames from 'classnames';
|
||||
import { AppLoader, DynamicLoader } from '../components/app-loader';
|
||||
import { Navbar } from '../components/navbar';
|
||||
|
||||
@@ -57,7 +57,7 @@ const Title = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const TransactionsHandler = () => {
|
||||
const InitializeHandlers = () => {
|
||||
useVegaTransactionManager();
|
||||
useVegaTransactionUpdater();
|
||||
useEthTransactionManager();
|
||||
@@ -93,7 +93,7 @@ function AppBody({ Component }: AppProps) {
|
||||
</div>
|
||||
<DialogsContainer />
|
||||
<ToastsManager />
|
||||
<TransactionsHandler />
|
||||
<InitializeHandlers />
|
||||
<MaybeConnectEagerly />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -7,7 +7,6 @@ interface GlobalStore {
|
||||
marketId: string | null;
|
||||
update: (store: Partial<Omit<GlobalStore, 'update'>>) => void;
|
||||
shouldDisplayWelcomeDialog: boolean;
|
||||
shouldDisplayAnnouncementBanner: boolean;
|
||||
}
|
||||
|
||||
interface PageTitleStore {
|
||||
@@ -19,7 +18,6 @@ export const useGlobalStore = create<GlobalStore>()((set) => ({
|
||||
nodeSwitcherDialog: false,
|
||||
marketId: LocalStorage.getItem('marketId') || null,
|
||||
shouldDisplayWelcomeDialog: false,
|
||||
shouldDisplayAnnouncementBanner: true,
|
||||
update: (newState) => {
|
||||
set(
|
||||
produce((state: GlobalStore) => {
|
||||
|
||||
+15
-3
@@ -1,10 +1,22 @@
|
||||
#!/bin/sh -eux
|
||||
#!/bin/bash -ex
|
||||
|
||||
export PATH="/app/node_modules/.bin:$PATH"
|
||||
|
||||
flags="--network-timeout 100000 --pure-lockfile"
|
||||
|
||||
if [[ ! -z "${ENV_NAME}" ]]; then
|
||||
flags="--env=${ENV_NAME} $flags"
|
||||
fi
|
||||
|
||||
if [ "${APP}" = "trading" ]; then
|
||||
yarn nx export ${APP} --network-timeout 100000 --pure-lockfile
|
||||
yarn nx export ${APP} $flags
|
||||
mv /app/dist/apps/trading/exported/ /app/tmp
|
||||
rm -rf /app/dist/apps/trading
|
||||
mv /app/tmp /app/dist/apps/trading
|
||||
else
|
||||
yarn nx build ${APP} --network-timeout 100000 --pure-lockfile
|
||||
yarn nx build ${APP} $flags
|
||||
fi
|
||||
|
||||
env_vars_file="/app/dist/apps/${APP}/.env"
|
||||
# make sure there are no exposed .env files
|
||||
rm $env_vars_file || echo "No env vars file"
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Recreate config file
|
||||
env_file=/usr/share/nginx/html/assets/env-config.js
|
||||
mkdir -p $(dirname $env_file)
|
||||
rm -rf $env_file || echo "no file to delete"
|
||||
touch $env_file
|
||||
|
||||
env_vars_file=/usr/share/nginx/html/.env
|
||||
sed -i '/^#/d' $env_vars_file # remove comment lines
|
||||
sed -i '/^$/d' $env_vars_file # remove empty lines
|
||||
|
||||
# Add assignment
|
||||
echo "window._env_ = {" >> $env_file
|
||||
|
||||
# Read each line in .env file
|
||||
# Each line represents key=value pairs
|
||||
while read -r line || [[ -n "$line" ]];
|
||||
do
|
||||
# Split env variables by character `=`
|
||||
if printf '%s\n' "$line" | grep -q -e '='; then
|
||||
varname=$(printf '%s\n' "$line" | sed -e 's/=.*//')
|
||||
varvalue=$(printf '%s\n' "$line" | sed -e 's/^[^=]*=//')
|
||||
fi
|
||||
|
||||
# Read value of current variable if exists as Environment variable
|
||||
value=$(printf '%s\n' "${!varname}")
|
||||
# Otherwise use value from .env file
|
||||
[[ -z $value ]] && value=${varvalue}
|
||||
|
||||
# Append configuration property to JS file if non-empty
|
||||
if [ ! -z "$varname" ]; then
|
||||
echo " $varname: \"$value\"," >> $env_file
|
||||
fi
|
||||
done < $env_vars_file
|
||||
|
||||
rm $env_vars_file
|
||||
|
||||
echo "}" >> $env_file
|
||||
|
||||
# start serving
|
||||
nginx -g 'daemon off;'
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"presets": ["@nrwl/next/babel"],
|
||||
"plugins": []
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
const rootMain = require('../../../.storybook/main');
|
||||
|
||||
module.exports = {
|
||||
...rootMain,
|
||||
|
||||
core: { ...rootMain.core, builder: 'webpack5' },
|
||||
|
||||
stories: [
|
||||
...rootMain.stories,
|
||||
'../src/lib/**/*.stories.mdx',
|
||||
'../src/lib/**/*.stories.@(js|jsx|ts|tsx)',
|
||||
],
|
||||
addons: [
|
||||
...rootMain.addons,
|
||||
'@nrwl/react/plugins/storybook',
|
||||
'storybook-addon-themes',
|
||||
],
|
||||
webpackFinal: async (config, { configType }) => {
|
||||
// apply any global webpack configs that might have been specified in .storybook/main.js
|
||||
if (rootMain.webpackFinal) {
|
||||
config = await rootMain.webpackFinal(config, { configType });
|
||||
}
|
||||
|
||||
// add your own webpack tweaks if needed
|
||||
|
||||
return config;
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
|
||||
@@ -0,0 +1,2 @@
|
||||
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
|
||||
export * from '../../ui-toolkit/.storybook/preview';
|
||||
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"emitDecoratorMetadata": true,
|
||||
"outDir": ""
|
||||
},
|
||||
"files": [
|
||||
"../../../node_modules/@nrwl/react/typings/styled-jsx.d.ts",
|
||||
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
|
||||
"../../../node_modules/@nrwl/react/typings/image.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"../**/*.spec.ts",
|
||||
"../**/*.spec.js",
|
||||
"../**/*.spec.tsx",
|
||||
"../**/*.spec.jsx",
|
||||
"jest.config.ts"
|
||||
],
|
||||
"include": ["../src/**/*", "*.js"]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user