Compare commits

..
680 changed files with 5545 additions and 14168 deletions
-16
View File
@@ -1,16 +0,0 @@
name: 'Check if branch is shorter than 52 chars'
on: pull_request
jobs:
branch-naming-rules:
runs-on: ubuntu-latest
steps:
# echo "branches that are longer than 51 chars can't be parsed by kubernetes to create previews. Each app has prefix of it's name like: 'governance-' (12 chars), what leaves 51 max branch length"
# current parsable length: $( git rev-parse --abbrev-ref HEAD | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | wc -c)
- uses: deepakputhraya/action-branch-name@master
with:
# regex: '([a-z])+\/([a-z])+' # Regex the branch should match. This example enforces grouping
# allowed_prefixes: 'feature,stable,fix' # All branches should start with the given prefix
# ignore: master,develop # Ignore exactly matching branch names from convention
min_length: 1 # Min length of the branch name
max_length: 51 # Max length of the branch name
+20 -41
View File
@@ -5,8 +5,6 @@ on:
branches: branches:
- release/* - release/*
- develop - develop
tags:
- v*
pull_request: pull_request:
types: types:
- opened - opened
@@ -52,7 +50,7 @@ jobs:
secrets: inherit secrets: inherit
lint-test-build: lint-test-build:
timeout-minutes: 60 timeout-minutes: 35
needs: node-modules needs: node-modules
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
name: '(CI) lint + unit test + build' name: '(CI) lint + unit test + build'
@@ -99,50 +97,27 @@ jobs:
- name: See affected apps - name: See affected apps
run: | run: |
echo ">>>> debug" echo ">>>> debug"
echo "NX Version: $nx_version"
echo "NX_BASE: ${{ env.NX_BASE }}" echo "NX_BASE: ${{ env.NX_BASE }}"
echo "NX_HEAD: ${{ env.NX_HEAD }}" echo "NX_HEAD: ${{ env.NX_HEAD }}"
echo ">>>> eof debug" echo ">>>> eof debug"
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)" affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)"
echo -n "Affected projects: $affected"
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
projects_e2e="" projects_e2e=""
preview_governance="not deployed" if [[ $affected == *"governance"* ]]; then projects_e2e+='"governance-e2e" '; fi
preview_trading="not deployed" if [[ $affected == *"trading"* ]]; then projects_e2e+='"trading-e2e" '; fi
preview_explorer="not deployed" if [[ $affected == *"explorer"* ]]; then projects_e2e+='"explorer-e2e" '; fi
if [[ -z "$projects_e2e" ]]; then if [[ -z "$projects_e2e" ]]; then projects_e2e+='"governance-e2e" "trading-e2e" "explorer-e2e" '; fi
projects_e2e+='"governance-e2e" "trading-e2e" "explorer-e2e" '
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
else
if [[ $affected == *"governance"* ]]; then
projects_e2e+='"governance-e2e" '
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
fi
if [[ $affected == *"trading"* ]]; then
projects_e2e+='"trading-e2e" '
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
fi
if [[ $affected == *"explorer"* ]]; then
projects_e2e+='"explorer-e2e" '
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
fi
fi
projects_e2e=${projects_e2e%?} projects_e2e=${projects_e2e%?}
projects_e2e=[${projects_e2e// /,}] projects_e2e=[${projects_e2e// /,}]
echo PROJECTS_E2E=$projects_e2e >> $GITHUB_ENV echo PROJECTS_E2E=$projects_e2e >> $GITHUB_ENV
echo PROJECTS=$(echo $projects_e2e | sed 's|-e2e||g') >> $GITHUB_ENV echo PROJECTS=$(echo $projects_e2e | sed 's|-e2e||g') >> $GITHUB_ENV
echo PREVIEW_GOVERNANCE=$preview_governance >> $GITHUB_ENV
echo PREVIEW_TRADING=$preview_trading >> $GITHUB_ENV
echo PREVIEW_EXPLORER=$preview_explorer >> $GITHUB_ENV
outputs: outputs:
projects: ${{ env.PROJECTS }} projects: ${{ env.PROJECTS }}
projects-e2e: ${{ env.PROJECTS_E2E }} projects-e2e: ${{ env.PROJECTS_E2E }}
preview_governance: ${{ env.PREVIEW_GOVERNANCE }}
preview_trading: ${{ env.PREVIEW_TRADING }}
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
cypress: cypress:
needs: lint-test-build needs: lint-test-build
@@ -165,9 +140,7 @@ jobs:
dist-check: dist-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs: publish-dist
- publish-dist
- lint-test-build
if: ${{ github.event_name == 'pull_request' }} if: ${{ github.event_name == 'pull_request' }}
name: '(CD) comment preview links' name: '(CD) comment preview links'
steps: steps:
@@ -178,16 +151,22 @@ jobs:
issue-number: ${{ github.event.pull_request.number }} issue-number: ${{ github.event.pull_request.number }}
body-includes: Previews body-includes: Previews
- name: Create comment - name: Inject slug/short variables
uses: peter-evans/create-or-update-comment@v3
if: ${{ steps.fc.outputs.comment-id == 0 }} if: ${{ steps.fc.outputs.comment-id == 0 }}
uses: rlespinasse/github-slug-action@v4
with:
prefix: CI_
- name: Create comment
if: ${{ steps.fc.outputs.comment-id == 0 }}
uses: peter-evans/create-or-update-comment@v3
with: with:
issue-number: ${{ github.event.pull_request.number }} issue-number: ${{ github.event.pull_request.number }}
body: | body: |
Previews: Previews
* governance: ${{ needs.lint-test-build.outputs.preview_governance }} - explorer https://explorer.${{ env.CI_GITHUB_REF_NAME }}.vega.rocks
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }} - trading https://trading.${{ env.CI_GITHUB_REF_NAME }}.vega.rocks
* trading: ${{ needs.lint-test-build.outputs.preview_trading }} - governance https://governance.${{ env.CI_GITHUB_REF_NAME }}.vega.rocks
cypress-check: cypress-check:
name: '(CI) cypress - check' name: '(CI) cypress - check'
+1
View File
@@ -33,4 +33,5 @@ jobs:
config: baseUrl=${{ github.event.inputs.url }} config: baseUrl=${{ github.event.inputs.url }}
env: grepTags=@live env: grepTags=@live
env: env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -66,7 +66,7 @@ jobs:
###### ######
- name: Run Cypress tests - name: Run Cypress tests
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --browser chrome --env.grepTags="${{ inputs.tags }}" run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome --env.grepTags="${{ inputs.tags }}"
working-directory: frontend-monorepo working-directory: frontend-monorepo
env: env:
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }} CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
+36 -89
View File
@@ -30,21 +30,13 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
- name: Log in to the Container registry (ghcr) - name: Log in to the Container registry
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to the Container registry (docker hub)
uses: docker/login-action@v2
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
with:
# registry: registry.hub.docker.com
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Setup node - name: Setup node
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
@@ -62,24 +54,30 @@ jobs:
- name: Define variables - name: Define variables
run: | run: |
envName='' envName=''
dockerfile="dist.Dockerfile"
if [[ "${{ github.event_name }}" = "push" ]]; then if [[ "${{ github.event_name }}" = "push" ]]; then
domain="vega.rocks" domain="vega.rocks"
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)" envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
if [[ "${{ github.ref }}" =~ .*mainnet.* ]]; then if [[ "${{ github.ref }}" =~ .*mainnet.* ]]; then
domain="vega.community" domain="vega.community"
if [[ "${{ matrix.app }}" = "trading" ]]; then
dockerfile="ipfs.Dockerfile"
fi
fi fi
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
envName="stagnet1" envName="stagnet3"
elif [[ "${{ matrix.app}}" = "trading" ]] && [[ ${{ startsWith(github.ref, 'refs/tags/v') && 'true' || 'false' }} = "true" ]]; then
envName="mainnet"
fi fi
bucketName="${{ matrix.app }}.${envName}.${domain}" bucketName="${{ matrix.app }}.${envName}.${domain}"
echo BUCKET_NAME=${bucketName} >> $GITHUB_ENV echo BUCKET_NAME=${bucketName} >> $GITHUB_ENV
fi fi
nodeVersion=$(cat .nvmrc | head -n 1)
echo ENV_NAME=${envName} >> $GITHUB_ENV echo ENV_NAME=${envName} >> $GITHUB_ENV
echo NODE_VERSION=${nodeVersion} >> $GITHUB_ENV
echo DOCKERFILE=docker/${dockerfile} >> $GITHUB_ENV
- name: Build local dist - name: Build local dist
if: ${{ env.DOCKERFILE != 'docker/ipfs.Dockerfile' }}
run: | run: |
flags="" flags=""
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
@@ -100,60 +98,62 @@ jobs:
- name: Build and export to local Docker - name: Build and export to local Docker
id: docker_build id: docker_build
if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
with: with:
context: . context: .
file: docker/node-outside-docker.Dockerfile file: ${{ env.DOCKERFILE }}
load: true load: true
build-args: | build-args: |
APP=${{ matrix.app }} APP=${{ matrix.app }}
NODE_VERSION=${{ env.NODE_VERSION }}
ENV_NAME=${{ env.ENV_NAME }} ENV_NAME=${{ env.ENV_NAME }}
tags: | tags: |
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
- name: Image digest - name: Image digest
if: ${{ github.event_name == 'pull_request' }} if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
run: echo ${{ steps.docker_build.outputs.digest }} run: echo ${{ steps.docker_build.outputs.digest }}
- name: Sanity check docker image - name: Sanity check docker image
if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
run: | run: |
echo "Check ipfs-hash" echo "Check ipfs-hash"
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash if [[ "${{ env.DOCKERFILE }}" = "docker/ipfs.Dockerfile" ]]; then
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash > ${{ matrix.app }}-ipfs-hash docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash
echo "List html directory" fi
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree /usr/share/nginx/html'
- name: Publish dist as docker image (ghcr) echo "List html directory"
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree .'
- name: Copy dist to local filesystem
if: ${{ env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' }}
run: |
docker create --name=dist ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
docker cp dist:/usr/share/nginx/html dist
echo "check local dist files"
tree dist/html
mv dist/html dist-result
- name: Publish dist as docker image
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
if: ${{ github.event_name == 'pull_request' || (matrix.app == 'trading' && github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/v') ) }} if: ${{ github.event_name == 'pull_request' }}
with: with:
context: . context: .
file: docker/node-outside-docker.Dockerfile file: ${{ env.DOCKERFILE }}
push: true push: true
build-args: | build-args: |
APP=${{ matrix.app }} APP=${{ matrix.app }}
NODE_VERSION=${{ env.NODE_VERSION }}
ENV_NAME=${{ env.ENV_NAME }} ENV_NAME=${{ env.ENV_NAME }}
tags: | tags: |
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ github.event.pull_request.head.sha || github.sha }} ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ github.event.pull_request.head.sha || github.sha }}
- name: Publish dist as docker image (docker hub)
uses: docker/build-push-action@v3
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
with:
context: .
file: docker/node-outside-docker.Dockerfile
push: true
build-args: |
APP=${{ matrix.app }}
ENV_NAME=${{ env.ENV_NAME }}
tags: |
vegaprotocol/${{ matrix.app }}:${{ github.ref_name }}
vegaprotocol/${{ matrix.app }}:mainnet
# bucket creation in github.com/vegaprotocol/terraform//frontend # bucket creation in github.com/vegaprotocol/terraform//frontend
- name: Publish dist to s3 - name: Publish dist to s3
uses: jakejarvis/s3-sync-action@master uses: jakejarvis/s3-sync-action@master
if: ${{ github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/v') }} if: ${{ github.event_name == 'push' }}
with: with:
args: --acl private --follow-symlinks --delete args: --acl private --follow-symlinks --delete
env: env:
@@ -169,56 +169,3 @@ jobs:
with: with:
labels: ${{ matrix.app }}-preview labels: ${{ matrix.app }}-preview
number: ${{ github.event.number }} number: ${{ github.event.number }}
- name: Add ipfs hash to release
uses: softprops/action-gh-release@v1
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
with:
files: ${{ matrix.app }}-ipfs-hash
- name: Trigger fleek deployment
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
run: |
# display info about app
curl -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"query": "query{getSiteById(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id latestDeploy{id status}}}"}' \
https://api.fleek.co/graphql
# trigger new deployment as base image is always set to vegaprotocol/trading:mainnet
curl -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
https://api.fleek.co/graphql
- name: Checkout vega.xyz
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
uses: actions/checkout@v3
with:
repository: vegaprotocol/vega.xyz
path: './vega-xyz'
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
- name: Update hash on interstitial page
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
env:
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
run: |
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
tar -xzf kubo.tgz
export PATH="$PATH:$PWD/kubo"
which ipfs
new_hash=$(cat ${{ matrix.app }}-ipfs-hash)
cd vega-xyz
./interstital-allow-update.sh ${new_hash}
git config --global user.email "vega-ci-bot@vega.xyz"
git config --global user.name "vega-ci-bot"
branch_name=${{ github.ref_name }}-hash-update
git checkout -b "${branch_name}"
git add interstitial-allow.json netlify.toml
commit_msg="feat(ci): Update CID for console release @ ${{ github.ref }}"
git commit -m "${commit_msg}"
git push -u origin "${branch_name}"
pr_url="$(gh pr create --title "${commit_msg}" --body 'update ipfs hash for console @ ${{ github.ref }}')"
echo $pr_url
gh pr merge --auto $pr_url
-1
View File
@@ -2,7 +2,6 @@
# compiled output # compiled output
/dist /dist
/dist-result
/tmp /tmp
/out-tsc /out-tsc
/tools/executors/**/*.js /tools/executors/**/*.js
+1
View File
@@ -7,4 +7,5 @@ __generated___
apps/static/src/assets/devnet-tranches.json apps/static/src/assets/devnet-tranches.json
apps/static/src/assets/mainnet-tranches.json apps/static/src/assets/mainnet-tranches.json
apps/static/src/assets/stagnet3-tranches.json
apps/static/src/assets/testnet-tranches.json apps/static/src/assets/testnet-tranches.json
Vendored
+19 -1
View File
@@ -1,2 +1,20 @@
@Library('vega-shared-library') _ @Library('vega-shared-library') _
runApprobation ignoreFailure: false, frontendBranch: env.BRANCH_NAME, type: 'frontend'
def commitHash = 'UNKNOWN'
pipeline {
agent any
options {
skipDefaultCheckout true
parallelsAlwaysFailFast()
}
stages {
stage('approbation') {
steps {
sh 'printenv'
checkout scm
runApprobation ignoreFailure: false, frontendBranch: env.BRANCH_NAME, type: 'frontend'
}
}
}
}
-20
View File
@@ -1,20 +0,0 @@
.PHONY: latest-release
latest-release:
gh release list | head -n 1 | awk '{print $1}'
.PHONY: show-latest-release
show-latest-release:
gh release view `gh release list | head -n 1 | awk '{print $1}'`
.PHONY: recalculate-ipfs
recalculate-ipfs:
echo "ipfs hash inside the image"
docker run --rm ${TAG} cat /ipfs-hash
echo "recalculating ipfs hash"
docker run --rm ${TAG} ipfs add -r /usr/share/nginx/html
.PHONY: eject-ipfs-hash
unpack:
docker create --name=dist ${TAG}
docker cp dist:/usr/share/nginx/html dist
docker rm dist
+13 -56
View File
@@ -72,7 +72,7 @@ Run `nx serve my-app` for a dev server. Navigate to the port specified in `app/<
In order to generate the schemas for your GraphQL queries, you can run `GRAPHQL_SCHEMA_PATH=[YOUR SCHEMA FILE / API URL HERE] nx run types:generate`. In order to generate the schemas for your GraphQL queries, you can run `GRAPHQL_SCHEMA_PATH=[YOUR SCHEMA FILE / API URL HERE] nx run types:generate`.
```bash ```bash
export GRAPHQL_SCHEMA_PATH=https://api.n07.testnet.vega.xyz/graphql export GRAPHQL_SCHEMA_PATH=https://api.n11.testnet.vega.xyz/graphql
yarn nx run types:generate yarn nx run types:generate
``` ```
@@ -103,68 +103,25 @@ In CI linting, formatting and also run. These checks can be seen in the [CI work
Visit the [Nx Documentation](https://nx.dev/getting-started/intro) to learn more. Visit the [Nx Documentation](https://nx.dev/getting-started/intro) to learn more.
# 🐋 Hosting a console # Docker & Vegacapsule
To host a console there are two possible build scenarios for running the frontends: nx performed **outside** or **inside** docker build. For specific build instructions follow [build instructions](#build-instructions). ## Docker
In order to run a container on port 3000: The [Dockerfile](./dockerfiles) for running the frontends is pretty basic, merely building the application with the APP arg that is passed in and serving the application from [nginx](./nginx/nginx.conf). The only complexity that exists is that there is a script which allows the passing of run time environment variables to the containers. See configuration below for how to do this.
You can build any of the containers locally with the following command:
```bash
docker build --dockerfile dockerfiles/Dockerfile.cra . --build-arg APP=[YOUR APP] --tag=[TAG]
```
In order to run a container:
```bash ```bash
docker run -p 3000:80 [TAG] docker run -p 3000:80 [TAG]
``` ```
## Build instructions Images ending with `.dist` are to pack locally created transpiled HTML files into nginx container for non-compatible with yarn architectures like M1 Mac
The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of console either for the web, or ready for pinning on IPFS
### nx build outside the docker
Packaging prepared dist into [`nginx`](https://hub.docker.com/_/nginx)([server configuration](./nginx/nginx.conf)) docker image involves building the application on docker host machine from source.
As a prerequisite you need to perform build of `dist` directory and move its content for specific application to `dist-result` directory. Use following script to do it with a single command:
```bash
./docker/prepare-dist.sh
```
You can build any of the containers locally with the following command:
```bash
docker build --dockerfile docker/node-outside-docker.Dockerfile . --tag=[TAG]
```
### nx build inside the docker
Using multistage dockerfile dist is compiled using [node](https://hub.docker.com/_/node) image and later packed to nginx as in [dist build](#dist-build) example.
```bash
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=$(cat .nvmrc) --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
```
### Computing ipfs-hash of the build
At the moment this feature is important only for `trading` (console) releases.
Each docker build finishes with hash calculation for dist directory. Resulting hash is added to file named as `/ipfs-hash`. Once docker image is produced you can run following commad to display ipfs-hash:
```bash
make recalculate-ipfs TAG=vegaprotocol/trading:{YOUR_VERSION}
```
**updating hash:** recompiling dist directory (even if there are no changed to source code) results in different hash computed by ipfs command.
### Verifying ipfs-hash of existing current application version
An IPFS CID will be attached to every [release](https://github.com/vegaprotocol/frontend-monorepo/releases). If you are intending to pin an application on IPFS, you can check that your build matches by running the following steps:
1. Show latest release by runnning: `make latest-release`. You need to configure [`gh`](https://cli.github.com/) for this step to work, otherwise please provide release manually from [github](https://github.com/vegaprotocol/frontend-monorepo/releases) or [dockerhub](https://hub.docker.com/r/vegaprotocol/trading)
2. Set RELEASE environment variable to value that you want to validate: `export RELEASE=$(make latest-release)` or `export RELEASE=vXX.XX.XX`
3. Set TAG environment variable to image that you want to validate: `export TAG=vegaprotocol/trading:$RELEASE`
4. Download docker image with the desired release `docker pull $TAG`.
5. Recalculate hash: `make recalculate-ipfs`
6. You should see exactly same hash produced by ipfs command as one placed with the release notes: `make show-latest-release`
7. If you want to extract dist from docker image to your local filesystem you can run following command: `make unpack`
8. Now `dist` directory contains valid application build. **it is not possible to calculate same ipfs hash on files that are result of copy operation**
## Config ## Config
+2 -2
View File
@@ -1,7 +1,7 @@
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
NX_TENDERMINT_URL=http://localhost:26617 NX_TENDERMINT_URL=http://localhost:26617
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
NX_VEGA_URL=http://localhost:3008/graphql NX_VEGA_URL=http://localhost:3028/query
NX_VEGA_ENV=CUSTOM NX_VEGA_ENV=CUSTOM
NX_VEGA_CONFIG_URL= NX_VEGA_CONFIG_URL=
@@ -18,4 +18,4 @@ NX_EXPLORER_PARTIES=1
NX_EXPLORER_VALIDATORS=1 NX_EXPLORER_VALIDATORS=1
CYPRESS_VEGA_WALLET_API_TOKEN= CYPRESS_VEGA_WALLET_API_TOKEN=
CYPRESS_VEGA_URL=http://localhost:3008/graphql CYPRESS_VEGA_URL=http://localhost:3028/query
+1 -1
View File
@@ -2,7 +2,7 @@
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
NX_TENDERMINT_URL=https://mainnet-observer-proxy01.ops.vega.xyz/ NX_TENDERMINT_URL=https://mainnet-observer-proxy01.ops.vega.xyz/
NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocket NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocket
NX_VEGA_URL=https://api.vega.community/graphql NX_VEGA_URL=https://api.vega.xyz/query
NX_VEGA_ENV=MAINNET NX_VEGA_ENV=MAINNET
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
+18
View File
@@ -0,0 +1,18 @@
# App configuration variables
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n00.stagnet3.vega.xyz/websocket
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET3
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
# App flags
NX_EXPLORER_ASSETS=1
NX_EXPLORER_GENESIS=1
NX_EXPLORER_GOVERNANCE=1
NX_EXPLORER_MARKETS=1
NX_EXPLORER_ORACLES=1
NX_EXPLORER_TXS_LIST=0
NX_EXPLORER_NETWORK_PARAMETERS=1
NX_EXPLORER_PARTIES=1
NX_EXPLORER_VALIDATORS=1
+1 -1
View File
@@ -2,7 +2,7 @@
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz/tm NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz/tm
NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
NX_VEGA_ENV=TESTNET NX_VEGA_ENV=TESTNET
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
+1 -1
View File
@@ -25,7 +25,7 @@ module.exports = defineConfig({
}, },
env: { env: {
environment: 'CUSTOM', environment: 'CUSTOM',
networkQueryUrl: 'http://localhost:3008/graphql', networkQueryUrl: 'http://localhost:3028/query',
ethUrl: 'https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8', ethUrl: 'https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
commitHash: 'dev', commitHash: 'dev',
tsConfig: 'tsconfig.json', tsConfig: 'tsconfig.json',
@@ -10,8 +10,6 @@
"governance.proposal.updateMarket.minVoterBalance", "governance.proposal.updateMarket.minVoterBalance",
"governance.proposal.updateNetParam.minProposerBalance", "governance.proposal.updateNetParam.minProposerBalance",
"governance.proposal.updateNetParam.minVoterBalance", "governance.proposal.updateNetParam.minVoterBalance",
"governance.proposal.updateAsset.minProposerBalance",
"governance.proposal.updateAsset.minVoterBalance",
"reward.staking.delegation.maxPayoutPerEpoch", "reward.staking.delegation.maxPayoutPerEpoch",
"reward.staking.delegation.maxPayoutPerParticipant", "reward.staking.delegation.maxPayoutPerParticipant",
"reward.staking.delegation.minimumValidatorStake", "reward.staking.delegation.minimumValidatorStake",
@@ -21,6 +19,9 @@
"validators.delegation.minAmount" "validators.delegation.minAmount"
], ],
"fiveDecimal": [ "fiveDecimal": [
"governance.proposal.updateAsset.minProposerBalance",
"governance.proposal.updateAsset.minVoterBalance",
"governance.proposal.updateAsset.requiredParticipation",
"market.fee.factors.infrastructureFee", "market.fee.factors.infrastructureFee",
"market.fee.factors.makerFee", "market.fee.factors.makerFee",
"market.liquidity.bondPenaltyParameter", "market.liquidity.bondPenaltyParameter",
@@ -76,7 +77,6 @@
"governance.proposal.updateNetParam.requiredMajority", "governance.proposal.updateNetParam.requiredMajority",
"governance.proposal.updateNetParam.requiredParticipation", "governance.proposal.updateNetParam.requiredParticipation",
"governance.proposal.updateMarket.minProposerEquityLikeShare", "governance.proposal.updateMarket.minProposerEquityLikeShare",
"governance.proposal.updateAsset.requiredParticipation",
"validators.vote.required" "validators.vote.required"
], ],
"duration": [ "duration": [
+46 -18
View File
@@ -9,22 +9,21 @@ context('Home Page', function () {
it('should show connected environment stats', function () { it('should show connected environment stats', function () {
const statTitles = { const statTitles = {
0: 'Status', 0: 'Status',
1: 'Epoch', 1: 'Block height',
2: 'Block height', 2: 'Uptime',
3: 'Uptime', 3: 'Total nodes',
4: 'Total nodes', 4: 'Total staked',
5: 'Total staked', 5: 'Backlog',
6: 'Backlog', 6: 'Trades / second',
7: 'Trades / second', 7: 'Orders / block',
8: 'Orders / block', 8: 'Orders / second',
9: 'Orders / second', 9: 'Transactions / block',
10: 'Transactions / block', 10: 'Block time',
11: 'Block time', 11: 'Time',
12: 'Time', 12: 'App',
13: 'App', 13: 'Tendermint',
14: 'Tendermint', 14: 'Up since',
15: 'Up since', 15: 'Chain ID',
16: 'Chain ID',
}; };
cy.get('[data-testid="stats-title"]') cy.get('[data-testid="stats-title"]')
@@ -32,13 +31,42 @@ context('Home Page', function () {
cy.wrap($list).should('contain.text', statTitles[index]); cy.wrap($list).should('contain.text', statTitles[index]);
}) })
.then(($list) => { .then(($list) => {
cy.wrap($list).should('have.length', 17); cy.wrap($list).should('have.length', 16);
}); });
cy.get(statsValue).eq(0).should('contain.text', 'CONNECTED');
cy.get(statsValue).eq(1).should('not.be.empty');
cy.get(statsValue)
.eq(2)
.invoke('text')
.should('match', /\d+d \d+h \d+m \d+s/i);
cy.get(statsValue).eq(3).should('contain.text', '2');
cy.get(statsValue)
.eq(4)
.invoke('text')
.should('match', /\d+\.\d\d(?!\d)/i);
cy.get(statsValue).eq(5).should('contain.text', '0');
cy.get(statsValue).eq(6).should('contain.text', '0');
cy.get(statsValue).eq(7).should('contain.text', '0');
cy.get(statsValue).eq(8).should('contain.text', '0');
cy.get(statsValue).eq(9).should('not.be.empty');
cy.get(statsValue).eq(10).should('not.be.empty');
cy.get(statsValue).eq(11).should('not.be.empty');
cy.get(statsValue)
.eq(12)
.invoke('text')
.should('match', /v\d+\.\d+\.\d+/i);
cy.get(statsValue)
.eq(13)
.invoke('text')
.should('match', /\d+\.\d+\.\d+/i);
cy.get(statsValue).eq(14).should('not.be.empty');
cy.get(statsValue).eq(15).should('not.be.empty');
}); });
it('Block height should be updating', function () { it('Block height should be updating', function () {
cy.get(statsValue) cy.get(statsValue)
.eq(2) .eq(1)
.invoke('text') .invoke('text')
.then((blockHeightTxt) => { .then((blockHeightTxt) => {
cy.get(statsValue) cy.get(statsValue)
@@ -138,7 +138,7 @@ context('Network parameters page', { tags: '@smoke' }, function () {
}); });
}); });
it.skip('should list each network parameter displayed as a currency value with four decimals - in the correct format', function () { it('should list each network parameter displayed as a currency value with four decimals - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => { cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters); network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => { network_parameters.forEach((network_parameter) => {
@@ -6,7 +6,7 @@ const customNodeBtn = 'custom-node';
context.skip('Node switcher', { tags: '@regression' }, function () { context.skip('Node switcher', { tags: '@regression' }, function () {
beforeEach('visit home page', function () { beforeEach('visit home page', function () {
cy.intercept('GET', 'https://static.vega.xyz/assets/capsule-network.json', { cy.intercept('GET', 'https://static.vega.xyz/assets/capsule-network.json', {
hosts: ['http://localhost:3008/graphql'], hosts: ['http://localhost:3028/query'],
}).as('nodeData'); }).as('nodeData');
cy.visit('/'); cy.visit('/');
cy.wait('@nodeData'); cy.wait('@nodeData');
@@ -219,7 +219,7 @@ context.skip('Parties page', { tags: '@regression' }, function () {
balance type asset {id symbol decimals}}}}}}}}'; balance type asset {id symbol decimals}}}}}}}}';
cy.request({ cy.request({
method: 'POST', method: 'POST',
url: `http://localhost:3008/graphql`, url: `http://localhost:3028/query`,
body: { body: {
query: mutation, query: mutation,
}, },
+8 -14
View File
@@ -1,19 +1,13 @@
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
NX_ETHERSCAN_URL=https://sepolia.etherscan.io 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='{"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 NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
NX_VEGA_ENV=STAGNET1
NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
NX_VEGA_TOKEN_URL=https://stagnet1.governance.vega.xyz
NX_VEGA_WALLET_URL=http://localhost:1789
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.xyz
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_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
NX_VEGA_GOVERNANCE_URL=https://stagnet1.governance.vega.xyz NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.jsoo
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
# App flags # App flags
NX_EXPLORER_ASSETS=1 NX_EXPLORER_ASSETS=1
+8 -1
View File
@@ -4,7 +4,14 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
NX_VEGA_ENV=CUSTOM NX_VEGA_ENV=CUSTOM
NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
NX_VEGA_EXPLORER_URL=/
# App flags # App flags
NX_EXPLORER_ASSETS=1
NX_EXPLORER_GENESIS=1
NX_EXPLORER_GOVERNANCE=1
NX_EXPLORER_MARKETS=1
NX_EXPLORER_ORACLES=1
NX_EXPLORER_TXS_LIST=0 NX_EXPLORER_TXS_LIST=0
NX_EXPLORER_NETWORK_PARAMETERS=1
NX_EXPLORER_PARTIES=1
NX_EXPLORER_VALIDATORS=1
+1 -2
View File
@@ -5,8 +5,7 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-inter
NX_VEGA_ENV=DEVNET NX_VEGA_ENV=DEVNET
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://dev.governance.vega.xyz NX_VEGA_GOVERNANCE_URL=https://dev.token.vega.xyz
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql 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_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 NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_EXPLORER_URL=/
+4 -6
View File
@@ -1,11 +1,9 @@
# App configuration variables # App configuration variables
NX_TENDERMINT_URL=https://be.vega.community NX_TENDERMINT_URL=https://be.explorer.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket NX_TENDERMINT_WEBSOCKET_URL=wss://be.explorer.vega.xyz/websocket
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
NX_VEGA_URL=https://api.vega.community/graphql
NX_VEGA_ENV=MAINNET NX_VEGA_ENV=MAINNET
NX_BLOCK_EXPLORER=https://be.vega.community/rest/ NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest/
NX_ETHERSCAN_URL=https://etherscan.io NX_ETHERSCAN_URL=https://etherscan.io
NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz NX_VEGA_GOVERNANCE_URL=https://token.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
+14 -2
View File
@@ -1,2 +1,14 @@
# .env is stagnet1, so there are no overrides required NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET3":"https://stagnet3.explorer.vega.xyz"}' NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
NX_VEGA_ENV=STAGNET1
NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
NX_VEGA_TOKEN_URL=https://stagnet1.token.vega.xyz
NX_VEGA_WALLET_URL=http://localhost:1789
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.xyz
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
+8
View File
@@ -0,0 +1,8 @@
NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.stagnet3.vega.xyz/websocket
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
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
+1 -2
View File
@@ -7,6 +7,5 @@ NX_VEGA_ENV=TESTNET
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf NX_VEGA_GOVERNANCE_URL=https://token.fairground.wtf
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
-1
View File
@@ -11,4 +11,3 @@ NX_VEGA_GOVERNANCE_URL=https://validator-testnet.governance.vega.xyz
NX_TENDERMINT_URL=https://tm-be.validators-testnet.vega.rocks NX_TENDERMINT_URL=https://tm-be.validators-testnet.vega.rocks
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
NX_VEGA_EXPLORER_URL=https://validator-testnet.explorer.vega.xyz/
-1
View File
@@ -5,4 +5,3 @@ NX_VEGA_ENV=CUSTOM
NX_BLOCK_EXPLORER= NX_BLOCK_EXPLORER=
NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
NX_VEGA_EXPLORER_URL=/
+2 -1
View File
@@ -35,11 +35,12 @@ Example configurations are provided here:
- [Devnet](./.env.devnet) - [Devnet](./.env.devnet)
- [Capsule](./.env.capsule) - [Capsule](./.env.capsule)
- [Testnet](./.env.testnet) - [Testnet](./.env.testnet)
- [Stagnet3](./.env.stagnet3)
For convenience, you can boot the app injecting one of the configurations above by running: For convenience, you can boot the app injecting one of the configurations above by running:
```bash ```bash
yarn nx run explorer:serve --env={env} # e.g. stagnet1 yarn nx run explorer:serve --env={env} # e.g. stagnet3
``` ```
There are a few different configuration options offered for this app: There are a few different configuration options offered for this app:
+2 -24
View File
@@ -1,18 +1,9 @@
import { import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment';
AppFailure,
NetworkLoader,
NodeGuard,
NodeSwitcherDialog,
useEnvironment,
useInitializeEnv,
useNodeSwitcherStore,
} from '@vegaprotocol/environment';
import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider'; import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider';
import { Loader, Splash } from '@vegaprotocol/ui-toolkit'; import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client'; import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
import { RouterProvider } from 'react-router-dom'; import { RouterProvider } from 'react-router-dom';
import { router } from './routes/router-config'; import { router } from './routes/router-config';
import { t } from '@vegaprotocol/i18n';
const splashLoading = ( const splashLoading = (
<Splash> <Splash>
@@ -21,23 +12,10 @@ const splashLoading = (
); );
function App() { function App() {
const { VEGA_URL } = useEnvironment();
const [nodeSwitcherOpen, setNodeSwitcherOpen] = useNodeSwitcherStore(
(store) => [store.dialogOpen, store.setDialogOpen]
);
return ( return (
<TendermintWebsocketProvider> <TendermintWebsocketProvider>
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}> <NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
<NodeGuard <RouterProvider router={router} fallbackElement={splashLoading} />
skeleton={<div>{t('Loading')}</div>}
failure={<AppFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />}
>
<RouterProvider router={router} fallbackElement={splashLoading} />
</NodeGuard>
<NodeSwitcherDialog
open={nodeSwitcherOpen}
setOpen={setNodeSwitcherOpen}
/>
</NetworkLoader> </NetworkLoader>
</TendermintWebsocketProvider> </TendermintWebsocketProvider>
); );
@@ -6,7 +6,6 @@ export type AssetBalanceProps = {
assetId: string; assetId: string;
price: string; price: string;
showAssetLink?: boolean; showAssetLink?: boolean;
showAssetSymbol?: boolean;
}; };
/** /**
@@ -17,21 +16,18 @@ const AssetBalance = ({
assetId, assetId,
price, price,
showAssetLink = true, showAssetLink = true,
showAssetSymbol = false,
}: AssetBalanceProps) => { }: AssetBalanceProps) => {
const { data: asset, loading } = useAssetDataProvider(assetId); const { data: asset } = useAssetDataProvider(assetId);
const label = const label =
!loading && asset && asset.decimals asset && asset.decimals
? addDecimalsFormatNumber(price, asset.decimals) ? addDecimalsFormatNumber(price, asset.decimals)
: price; : price;
return ( return (
<div className="inline-block"> <div className="inline-block">
<span>{label}</span>{' '} <span>{label}</span>{' '}
{showAssetLink && asset?.id ? ( {showAssetLink && asset?.id ? <AssetLink assetId={assetId} /> : null}
<AssetLink showAssetSymbol={showAssetSymbol} assetId={assetId} />
) : null}
</div> </div>
); );
}; };
@@ -13,17 +13,11 @@ const DEFAULT_DECIMALS = 18;
* the governance asset first, which is set by a network parameter * the governance asset first, which is set by a network parameter
*/ */
const GovernanceAssetBalance = ({ price }: GovernanceAssetBalanceProps) => { const GovernanceAssetBalance = ({ price }: GovernanceAssetBalanceProps) => {
const { data, loading } = useExplorerGovernanceAssetQuery(); const { data } = useExplorerGovernanceAssetQuery();
if (!loading && data && data.networkParameter?.value) { if (data && data.networkParameter?.value) {
const governanceAssetId = data.networkParameter.value; const governanceAssetId = data.networkParameter.value;
return ( return <AssetBalance price={price} assetId={governanceAssetId} />;
<AssetBalance
price={price}
showAssetSymbol={true}
assetId={governanceAssetId}
/>
);
} else { } else {
return ( return (
<div className="inline-block"> <div className="inline-block">
@@ -4,7 +4,7 @@ import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit'; import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import { AgGridColumn } from 'ag-grid-react'; import { AgGridColumn } from 'ag-grid-react';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid'; import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
import { useRef, useLayoutEffect } from 'react'; import { useRef, useLayoutEffect } from 'react';
import { BREAKPOINT_MD } from '../../config/breakpoints'; import { BREAKPOINT_MD } from '../../config/breakpoints';
@@ -1,19 +1,13 @@
import { import { NodeSwitcherDialog, useEnvironment } from '@vegaprotocol/environment';
useEnvironment,
useNodeSwitcherStore,
} from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useScreenDimensions } from '@vegaprotocol/react-helpers'; import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import { ExternalLink, Link } from '@vegaprotocol/ui-toolkit'; import { ExternalLink, Link } from '@vegaprotocol/ui-toolkit';
import { useMemo } from 'react'; import { useMemo, useState } from 'react';
import { ENV } from '../../config/env'; import { ENV } from '../../config/env';
export const Footer = () => { export const Footer = () => {
const { VEGA_URL, GIT_COMMIT_HASH, GIT_ORIGIN_URL } = useEnvironment(); const { VEGA_URL, GIT_COMMIT_HASH, GIT_ORIGIN_URL } = useEnvironment();
const setNodeSwitcherOpen = useNodeSwitcherStore( const [nodeSwitcherOpen, setNodeSwitcherOpen] = useState(false);
(store) => store.setDialogOpen
);
const { screenSize } = useScreenDimensions(); const { screenSize } = useScreenDimensions();
const showFullFeedbackLabel = useMemo( const showFullFeedbackLabel = useMemo(
() => ['md', 'lg', 'xl', 'xxl', 'xxxl'].includes(screenSize), () => ['md', 'lg', 'xl', 'xxl', 'xxxl'].includes(screenSize),
@@ -21,40 +15,46 @@ export const Footer = () => {
); );
return ( return (
<footer className="grid grid-rows-2 grid-cols-[1fr_auto] text-xs md:text-md md:flex md:col-span-2 px-4 py-2 gap-4 border-t border-vega-light-200 dark:border-vega-dark-200"> <>
<div className="flex justify-between gap-2 align-middle"> <footer className="grid grid-rows-2 grid-cols-[1fr_auto] text-xs md:text-md md:flex md:col-span-2 px-4 py-2 gap-4 border-t border-vega-light-200 dark:border-vega-dark-200">
{GIT_COMMIT_HASH && ( <div className="flex justify-between gap-2 align-middle">
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4"> {GIT_COMMIT_HASH && (
<p data-testid="git-commit-hash"> <div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
{t('Version')}:{' '} <p data-testid="git-commit-hash">
<Link {t('Version')}:{' '}
href={ <Link
GIT_ORIGIN_URL href={
? `${GIT_ORIGIN_URL}/commit/${GIT_COMMIT_HASH}` GIT_ORIGIN_URL
: undefined ? `${GIT_ORIGIN_URL}/commit/${GIT_COMMIT_HASH}`
} : undefined
target={GIT_ORIGIN_URL ? '_blank' : undefined} }
> target={GIT_ORIGIN_URL ? '_blank' : undefined}
{GIT_COMMIT_HASH} >
</Link> {GIT_COMMIT_HASH}
</p> </Link>
</p>
</div>
)}
<div className="content-center flex pl-2 md:border-r border-neutral-700 dark:border-neutral-300 pr-4">
{VEGA_URL && <NodeUrl url={VEGA_URL} />}
<Link className="ml-2" onClick={() => setNodeSwitcherOpen(true)}>
{t('Change')}
</Link>
</div> </div>
)}
<div className="content-center flex pl-2 md:border-r border-neutral-700 dark:border-neutral-300 pr-4"> <div className="flex pl-2 content-center">
{VEGA_URL && <NodeUrl url={VEGA_URL} />} <ExternalLink href={ENV.addresses.feedback}>
<Link className="ml-2" onClick={() => setNodeSwitcherOpen(true)}> {showFullFeedbackLabel ? t('Share your feedback') : t('Feedback')}
{t('Change')} </ExternalLink>
</Link> </div>
</div> </div>
</footer>
<div className="flex pl-2 content-center"> <NodeSwitcherDialog
<ExternalLink href={ENV.addresses.feedback}> open={nodeSwitcherOpen}
{showFullFeedbackLabel ? t('Share your feedback') : t('Feedback')} setOpen={setNodeSwitcherOpen}
</ExternalLink> />
</div> </>
</div>
</footer>
); );
}; };
@@ -43,7 +43,7 @@ export const AssetLink = ({
if (asDialog) { if (asDialog) {
open(assetId, e.target as HTMLElement); open(assetId, e.target as HTMLElement);
} else { } else {
navigate(`/${Routes.ASSETS}/${asset?.id}`); navigate(`${Routes.ASSETS}/${asset?.id}`);
} }
}} }}
{...props} {...props}
@@ -14,72 +14,11 @@ import {
SettlementAssetInfoPanel, SettlementAssetInfoPanel,
} from '@vegaprotocol/market-info'; } from '@vegaprotocol/market-info';
import { MarketInfoTable } from '@vegaprotocol/market-info'; import { MarketInfoTable } from '@vegaprotocol/market-info';
import type { DataSourceDefinition } from '@vegaprotocol/types'; import { Link } from 'react-router-dom';
import isEqual from 'lodash/isEqual';
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => { export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
if (!market) return null; if (!market) return null;
const settlementData =
market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData
.data;
const terminationData =
market.tradableInstrument.instrument.product
.dataSourceSpecForTradingTermination.data;
const getSigners = (data: DataSourceDefinition) => {
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
const signers = data.sourceType.sourceType.signers || [];
return signers.map(({ signer }, i) => {
return (
(signer.__typename === 'ETHAddress' && signer.address) ||
(signer.__typename === 'PubKey' && signer.key)
);
});
}
return [];
};
const oraclePanels = isEqual(
getSigners(settlementData),
getSigners(terminationData)
)
? [
{
title: t('Settlement Oracle'),
content: (
<OracleInfoPanel
noBorder={false}
market={market}
type="settlementData"
/>
),
},
{
title: t('Termination Oracle'),
content: (
<OracleInfoPanel
noBorder={false}
market={market}
type="termination"
/>
),
},
]
: [
{
title: t('Oracle'),
content: (
<OracleInfoPanel
noBorder={false}
market={market}
type="settlementData"
/>
),
},
];
const panels = [ const panels = [
{ {
title: t('Key details'), title: t('Key details'),
@@ -157,7 +96,25 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
<LiquidityPriceRangeInfoPanel market={market} noBorder={false} /> <LiquidityPriceRangeInfoPanel market={market} noBorder={false} />
), ),
}, },
...oraclePanels, {
title: t('Oracle'),
content: (
<OracleInfoPanel noBorder={false} market={market}>
<Link
className="text-xs hover:underline"
to={`/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData.id}`}
>
{t('View settlement data oracle specification')}
</Link>
<Link
className="text-xs hover:underline"
to={`/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForTradingTermination.id}`}
>
{t('View termination oracle specification')}
</Link>
</OracleInfoPanel>
),
},
]; ];
return ( return (
@@ -3,7 +3,7 @@ import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit'; import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import { AgGridColumn } from 'ag-grid-react'; import { AgGridColumn } from 'ag-grid-react';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
import type { import type {
VegaICellRendererParams, VegaICellRendererParams,
VegaValueGetterParams, VegaValueGetterParams,
@@ -9,7 +9,7 @@ import SizeInMarket from '../size-in-market/size-in-market';
export interface DeterministicOrderDetailsProps { export interface DeterministicOrderDetailsProps {
id: string; id: string;
// Version to fetch, with 0 being 'latest' and 1 being 'first'. Defaults to 0 // Version to fetch, with 0 being 'latest' and 1 being 'first'. Defaults to 0
version?: number | null; version?: number;
} }
export const wrapperClasses = export const wrapperClasses =
@@ -28,7 +28,7 @@ export const wrapperClasses =
*/ */
const DeterministicOrderDetails = ({ const DeterministicOrderDetails = ({
id, id,
version = null, version = 0,
}: DeterministicOrderDetailsProps) => { }: DeterministicOrderDetailsProps) => {
const { data, error } = useExplorerDeterministicOrderQuery({ const { data, error } = useExplorerDeterministicOrderQuery({
variables: { orderId: id, version }, variables: { orderId: id, version },
@@ -20,7 +20,7 @@ export const PageHeader = ({
copy = false, copy = false,
className, className,
}: PageHeaderProps) => { }: PageHeaderProps) => {
const titleClasses = 'text-xl uppercase font-alpha calt'; const titleClasses = 'text-4xl xl:text-5xl uppercase font-alpha calt';
return ( return (
<header className={className}> <header className={className}>
<span className={`${titleClasses} block`}>{prefix}</span> <span className={`${titleClasses} block`}>{prefix}</span>
@@ -3,7 +3,7 @@ import { VoteProgress } from '@vegaprotocol/proposals';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import { AgGridColumn } from 'ag-grid-react'; import { AgGridColumn } from 'ag-grid-react';
import { ExternalLink } from '@vegaprotocol/ui-toolkit'; import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
import type { import type {
VegaICellRendererParams, VegaICellRendererParams,
VegaValueFormatterParams, VegaValueFormatterParams,
@@ -12,10 +12,7 @@ import { useLayoutEffect, useMemo, useRef, useState } from 'react';
import type { RowClickedEvent } from 'ag-grid-community'; import type { RowClickedEvent } from 'ag-grid-community';
import { getDateTimeFormat } from '@vegaprotocol/utils'; import { getDateTimeFormat } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { import { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers';
NetworkParams,
useNetworkParams,
} from '@vegaprotocol/network-parameters';
import { ProposalStateMapping } from '@vegaprotocol/types'; import { ProposalStateMapping } from '@vegaprotocol/types';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment'; import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
@@ -1,5 +1,3 @@
import { Icon } from '@vegaprotocol/ui-toolkit';
// https://github.com/vegaprotocol/vega/blob/develop/core/blockchain/response.go // https://github.com/vegaprotocol/vega/blob/develop/core/blockchain/response.go
export const ErrorCodes = new Map([ export const ErrorCodes = new Map([
[51, 'Transaction failed validation'], [51, 'Transaction failed validation'],
@@ -30,11 +28,7 @@ export const ChainResponseCode = ({
}: ChainResponseCodeProps) => { }: ChainResponseCodeProps) => {
const isSuccess = successCodes.has(code); const isSuccess = successCodes.has(code);
const icon = isSuccess ? ( const icon = isSuccess ? '✅' : '❌';
<Icon name="tick-circle" className="fill-vega-green-550" />
) : (
<Icon name="cross" className="fill-vega-pink-550" />
);
const label = ErrorCodes.get(code) || 'Unknown response code'; const label = ErrorCodes.get(code) || 'Unknown response code';
// Hack for batches with many errors - see https://github.com/vegaprotocol/vega/issues/7245 // Hack for batches with many errors - see https://github.com/vegaprotocol/vega/issues/7245
@@ -42,7 +36,7 @@ export const ChainResponseCode = ({
error && error.length > 100 ? error.replace(/,/g, ',\r\n') : error; error && error.length > 100 ? error.replace(/,/g, ',\r\n') : error;
return ( return (
<div title={`Response code: ${code} - ${label}`} className=" inline-block"> <div title={`Response code: ${code} - ${label}`} className="inline-block">
<span <span
className="mr-2" className="mr-2"
aria-label={isSuccess ? 'Success' : 'Warning'} aria-label={isSuccess ? 'Success' : 'Warning'}
@@ -30,7 +30,7 @@ export const BundleExists = ({
// Note if this is wrong, the wrong decoder will be used which will give incorrect data // Note if this is wrong, the wrong decoder will be used which will give incorrect data
return ( return (
<div className="w-auto h-10 max-w-lg border-2 border-solid border-vega-light-100 dark:border-vega-dark-200 p-5 mt-5"> <div className="w-auto max-w-lg border-2 border-solid border-vega-light-100 dark:border-vega-dark-200 p-5 mt-5">
<IconForBundleStatus status={status} /> <IconForBundleStatus status={status} />
<h1 className="text-xl pb-1"> <h1 className="text-xl pb-1">
{status === 'STATUS_ENABLED' {status === 'STATUS_ENABLED'
@@ -4,7 +4,6 @@ import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint
import { TxDetailsShared } from './shared/tx-details-shared'; import { TxDetailsShared } from './shared/tx-details-shared';
import { TableCell, TableRow, TableWithTbody } from '../../table'; import { TableCell, TableRow, TableWithTbody } from '../../table';
import ProposalLink from '../../links/proposal-link/proposal-link'; import ProposalLink from '../../links/proposal-link/proposal-link';
import { VoteIcon } from '../../vote-icon/vote-icon';
interface TxProposalVoteProps { interface TxProposalVoteProps {
txData: BlockExplorerTransactionResult | undefined; txData: BlockExplorerTransactionResult | undefined;
@@ -31,22 +30,27 @@ export const TxProposalVote = ({
return <>{t('Awaiting Block Explorer transaction details')}</>; return <>{t('Awaiting Block Explorer transaction details')}</>;
} }
const vote = txData.command.voteSubmission.value === 'VALUE_YES'; const vote = txData.command.voteSubmission.value ? '👍' : '👎';
return ( return (
<TableWithTbody className="mb-8" allowWrap={true}> <TableWithTbody className="mb-8" allowWrap={true}>
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} /> <TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
<TableRow modifier="bordered">
<TableCell>{t('Proposal ID')}</TableCell>
<TableCell>{txData.command.voteSubmission.proposalId}</TableCell>
</TableRow>
<TableRow modifier="bordered"> <TableRow modifier="bordered">
<TableCell>{t('Proposal details')}</TableCell> <TableCell>{t('Proposal details')}</TableCell>
<TableCell> <TableCell>
<ProposalLink id={txData.command.voteSubmission.proposalId} /> <ProposalLink id={txData.command.voteSubmission.proposalId} />
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow modifier="bordered">
<TableCell>{t('Proposal')}</TableCell>
<TableCell>{txData.command.voteSubmission.proposalId}</TableCell>
</TableRow>
<TableRow modifier="bordered"> <TableRow modifier="bordered">
<TableCell>{t('Vote')}</TableCell> <TableCell>{t('Vote')}</TableCell>
<TableCell> <TableCell>{vote}</TableCell>
<VoteIcon vote={vote} />
</TableCell>
</TableRow> </TableRow>
</TableWithTbody> </TableWithTbody>
); );
@@ -1,3 +1,4 @@
export { TxList } from './tx-list';
export { TxOrderType } from './tx-order-type'; export { TxOrderType } from './tx-order-type';
export { TxsInfiniteList } from './txs-infinite-list'; export { TxsInfiniteList } from './txs-infinite-list';
export { TxsInfiniteListItem } from './txs-infinite-list-item'; export { TxsInfiniteListItem } from './txs-infinite-list-item';
@@ -0,0 +1,14 @@
import { t } from '@vegaprotocol/i18n';
import type { TendermintUnconfirmedTransactionsResponse } from '../../routes/txs/tendermint-unconfirmed-transactions-response.d';
interface TxsProps {
data: TendermintUnconfirmedTransactionsResponse | undefined;
}
export const TxList = ({ data }: TxsProps) => {
if (!data) {
return <div>{t('Awaiting transactions')}</div>;
}
return <div>{JSON.stringify(data, null, ' ')}</div>;
};
@@ -1,6 +1,5 @@
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import type { components } from '../../../types/explorer'; import type { components } from '../../../types/explorer';
import { VoteIcon } from '../vote-icon/vote-icon';
interface TxOrderTypeProps { interface TxOrderTypeProps {
orderType: string; orderType: string;
@@ -138,15 +137,12 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
let type = displayString[orderType] || orderType; let type = displayString[orderType] || orderType;
let colours = let colours =
'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-250'; 'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-150';
// This will get unwieldy and should probably produce a different colour of tag // This will get unwieldy and should probably produce a different colour of tag
if (type === 'Chain Event' && !!command?.chainEvent) { if (type === 'Chain Event' && !!command?.chainEvent) {
type = getLabelForChainEvent(command.chainEvent); type = getLabelForChainEvent(command.chainEvent);
colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink'; colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink';
} else if (type === 'Validator Heartbeat') {
colours =
'text-white dark-text-white bg-vega-light-200 dark:bg-vega-dark-100';
} else if (type === 'Proposal' || type === 'Governance Proposal') { } else if (type === 'Proposal' || type === 'Governance Proposal') {
if (command && !!command.proposalSubmission) { if (command && !!command.proposalSubmission) {
type = getLabelForProposal(command.proposalSubmission); type = getLabelForProposal(command.proposalSubmission);
@@ -154,16 +150,6 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
colours = 'text-black bg-vega-yellow'; colours = 'text-black bg-vega-yellow';
} }
if (type === 'Vote on Proposal') {
return (
<VoteIcon
vote={command?.voteSubmission?.value === 'VALUE_YES'}
yesText="Proposal vote"
noText="Proposal vote"
/>
);
}
if (type === 'Vote on Proposal' || type === 'Vote Submission') { if (type === 'Vote on Proposal' || type === 'Vote Submission') {
colours = 'text-black bg-vega-yellow'; colours = 'text-black bg-vega-yellow';
} }
@@ -98,6 +98,6 @@ describe('Txs infinite list item', () => {
expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey'); expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey');
expect(screen.getByTestId('tx-type')).toHaveTextContent('testType'); expect(screen.getByTestId('tx-type')).toHaveTextContent('testType');
expect(screen.getByTestId('tx-block')).toHaveTextContent('1'); expect(screen.getByTestId('tx-block')).toHaveTextContent('1');
expect(screen.getByTestId('tx-success')).toHaveTextContent('Success'); expect(screen.getByTestId('tx-success')).toHaveTextContent('Success: ✅');
}); });
}); });
@@ -7,7 +7,7 @@ import { toHex } from '../search/detect-search';
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code'; import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
import isNumber from 'lodash/isNumber'; import isNumber from 'lodash/isNumber';
const TRUNCATE_LENGTH = 10; const TRUNCATE_LENGTH = 5;
export const TxsInfiniteListItem = ({ export const TxsInfiniteListItem = ({
hash, hash,
@@ -31,13 +31,13 @@ export const TxsInfiniteListItem = ({
return ( return (
<div <div
data-testid="transaction-row" data-testid="transaction-row"
className="flex items-center h-full border-t border-neutral-600 dark:border-neutral-800 txs-infinite-list-item grid grid-cols-10" className="flex items-center h-full border-t border-neutral-600 dark:border-neutral-800 txs-infinite-list-item grid grid-cols-10 py-2"
> >
<div <div
className="text-sm col-span-10 md:col-span-3 leading-none" className="text-sm col-span-10 xl:col-span-3 leading-none"
data-testid="tx-hash" data-testid="tx-hash"
> >
<span className="md:hidden uppercase text-vega-dark-300"> <span className="xl:hidden uppercase text-vega-dark-300">
ID:&nbsp; ID:&nbsp;
</span> </span>
<TruncatedLink <TruncatedLink
@@ -48,10 +48,10 @@ export const TxsInfiniteListItem = ({
/> />
</div> </div>
<div <div
className="text-sm col-span-10 md:col-span-3 leading-none" className="text-sm col-span-10 xl:col-span-3 leading-none"
data-testid="pub-key" data-testid="pub-key"
> >
<span className="md:hidden uppercase text-vega-dark-300"> <span className="xl:hidden uppercase text-vega-dark-300">
By:&nbsp; By:&nbsp;
</span> </span>
<TruncatedLink <TruncatedLink
@@ -61,14 +61,14 @@ export const TxsInfiniteListItem = ({
endChars={TRUNCATE_LENGTH} endChars={TRUNCATE_LENGTH}
/> />
</div> </div>
<div className="text-sm col-span-5 md:col-span-2 leading-none flex items-center"> <div className="text-sm col-span-5 xl:col-span-2 leading-none flex items-center">
<TxOrderType orderType={type} command={command} /> <TxOrderType orderType={type} command={command} />
</div> </div>
<div <div
className="text-sm col-span-3 md:col-span-1 leading-none flex items-center" className="text-sm col-span-3 xl:col-span-1 leading-none flex items-center"
data-testid="tx-block" data-testid="tx-block"
> >
<span className="md:hidden uppercase text-vega-dark-300"> <span className="xl:hidden uppercase text-vega-dark-300">
Block:&nbsp; Block:&nbsp;
</span> </span>
<TruncatedLink <TruncatedLink
@@ -79,11 +79,11 @@ export const TxsInfiniteListItem = ({
/> />
</div> </div>
<div <div
className="text-sm col-span-2 md:col-span-1 leading-none flex items-center" className="text-sm col-span-2 xl:col-span-1 leading-none flex items-center"
data-testid="tx-success" data-testid="tx-success"
> >
<span className="md:hidden uppercase text-vega-dark-300"> <span className="xl:hidden uppercase text-vega-dark-300">
Success&nbsp; Success:&nbsp;
</span> </span>
{isNumber(code) ? ( {isNumber(code) ? (
<ChainResponseCode code={code} hideLabel={true} /> <ChainResponseCode code={code} hideLabel={true} />
@@ -64,7 +64,9 @@ describe('Txs infinite list', () => {
error={Error('test error!')} error={Error('test error!')}
/> />
); );
expect(screen.getByText('Cannot fetch transaction')).toBeInTheDocument(); expect(
screen.getByText('Cannot fetch transaction: Error: test error!')
).toBeInTheDocument();
}); });
it('item renders data of n length into list of n length', () => { it('item renders data of n length into list of n length', () => {
@@ -30,7 +30,7 @@ const NOOP = () => {};
const Item = ({ index, style, isLoading, error }: ItemProps) => { const Item = ({ index, style, isLoading, error }: ItemProps) => {
let content; let content;
if (error) { if (error) {
content = t(`Cannot fetch transaction`); content = t(`Cannot fetch transaction: ${error}`);
} else if (isLoading) { } else if (isLoading) {
content = <Loader />; content = <Loader />;
} else { } else {
@@ -68,7 +68,7 @@ export const TxsInfiniteList = ({
className, className,
}: TxsInfiniteListProps) => { }: TxsInfiniteListProps) => {
const { screenSize } = useScreenDimensions(); const { screenSize } = useScreenDimensions();
const isStacked = ['xs', 'sm'].includes(screenSize); const isStacked = ['xs', 'sm', 'md', 'lg'].includes(screenSize);
if (!txs) { if (!txs) {
if (!areTxsLoading) { if (!areTxsLoading) {
@@ -95,15 +95,15 @@ export const TxsInfiniteList = ({
return ( return (
<div className={className} data-testid="transactions-list"> <div className={className} data-testid="transactions-list">
<div className="lg:grid grid-cols-10 w-full mb-3 hidden text-vega-dark-300 uppercase"> <div className="xl:grid grid-cols-10 w-full mb-3 hidden text-vega-dark-300 uppercase">
<div className="col-span-3"> <div className="col-span-3">
<span className="hidden xl:inline">{t('Transaction')} &nbsp;</span> <span className="hidden xl:inline">Transaction &nbsp;</span>
<span>ID</span> <span>ID</span>
</div> </div>
<div className="col-span-3">{t('Submitted By')}</div> <div className="col-span-3">Submitted By</div>
<div className="col-span-2">{t('Type')}</div> <div className="col-span-2">Type</div>
<div className="col-span-1">{t('Block')}</div> <div className="col-span-1">Block</div>
<div className="col-span-1">{t('Success')}</div> <div className="col-span-1">Success</div>
</div> </div>
<div data-testid="infinite-scroll-wrapper"> <div data-testid="infinite-scroll-wrapper">
<InfiniteLoader <InfiniteLoader
@@ -1,4 +1,5 @@
import { Routes } from '../../routes/route-names'; import { Routes } from '../../routes/route-names';
import { RenderFetched } from '../render-fetched';
import { TruncatedLink } from '../truncate/truncated-link'; import { TruncatedLink } from '../truncate/truncated-link';
import { TxOrderType } from './tx-order-type'; import { TxOrderType } from './tx-order-type';
import { Table, TableRow, TableCell } from '../table'; import { Table, TableRow, TableCell } from '../table';
@@ -8,7 +9,7 @@ import type { BlockExplorerTransactions } from '../../routes/types/block-explore
import isNumber from 'lodash/isNumber'; import isNumber from 'lodash/isNumber';
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code'; import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
import { getTxsDataUrl } from '../../hooks/use-txs-data'; import { getTxsDataUrl } from '../../hooks/use-txs-data';
import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit'; import { Loader } from '@vegaprotocol/ui-toolkit';
import EmptyList from '../empty-list/empty-list'; import EmptyList from '../empty-list/empty-list';
interface TxsPerBlockProps { interface TxsPerBlockProps {
@@ -26,7 +27,7 @@ export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
} = useFetch<BlockExplorerTransactions>(url); } = useFetch<BlockExplorerTransactions>(url);
return ( return (
<AsyncRenderer data={data} error={error} loading={!!loading}> <RenderFetched error={error} loading={loading} className="text-body-large">
{data && data.transactions.length > 0 ? ( {data && data.transactions.length > 0 ? (
<div className="overflow-x-auto whitespace-nowrap mb-28"> <div className="overflow-x-auto whitespace-nowrap mb-28">
<Table> <Table>
@@ -94,6 +95,6 @@ export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
label={t('0 transactions')} label={t('0 transactions')}
/> />
)} )}
</AsyncRenderer> </RenderFetched>
); );
}; };
@@ -1,37 +0,0 @@
import { render } from '@testing-library/react';
import { VoteIcon } from './vote-icon';
describe('Vote TX icon', () => {
it('should use the text For by default for yes votes', () => {
const yes = render(<VoteIcon vote={true} />);
expect(yes.getByTestId('label')).toHaveTextContent('For');
});
it('should use the yesText for yes votes if specified', () => {
const yes = render(<VoteIcon vote={true} yesText="Test" />);
expect(yes.getByTestId('label')).toHaveTextContent('Test');
});
it('should display the tick icon for yes votes', () => {
const no = render(<VoteIcon vote={true} />);
expect(no.getByRole('img')).toHaveAttribute(
'aria-label',
'tick-circle icon'
);
});
it('should use the text Against by default for no votes', () => {
const no = render(<VoteIcon vote={false} />);
expect(no.getByTestId('label')).toHaveTextContent('Against');
});
it('should use the noText for no votes if specified', () => {
const no = render(<VoteIcon vote={false} noText="Test" />);
expect(no.getByTestId('label')).toHaveTextContent('Test');
});
it('should display the delete icon for no votes', () => {
const no = render(<VoteIcon vote={false} />);
expect(no.getByRole('img')).toHaveAttribute('aria-label', 'delete icon');
});
});
@@ -1,40 +0,0 @@
import { Icon } from '@vegaprotocol/ui-toolkit';
import type { IconName } from '@vegaprotocol/ui-toolkit';
export interface VoteIconProps {
// True is a yes vote, false is undefined or no vorte
vote: boolean;
// Defaults to 'For', but can be any text
yesText?: string;
// Defaults to 'Against', but can be any text
noText?: string;
}
/**
* Displays a lozenge with an icon representing the way a user voted for a proposal.
* The yes and no text can be overridden
*
* @returns
*/
export function VoteIcon({
vote,
yesText = 'For',
noText = 'Against',
}: VoteIconProps) {
const label = vote ? yesText : noText;
const bg = vote ? 'bg-vega-green-550' : 'bg-vega-pink-550';
const icon: IconName = vote ? 'tick-circle' : 'delete';
const fill = vote ? 'vega-green-300' : 'vega-pink-300';
const text = vote ? 'vega-green-200' : 'vega-pink-200';
return (
<div
className={`voteicon inline-block my-1 py-1 px-2 py rounded-md text-white leading-one sm align-top ${bg}`}
>
<Icon name={icon} size={3} className={`mr-2 p-0 fill-${fill}`} />
<span className={`text-base text-${text}`} data-testid="label">
{label}
</span>
</div>
);
}
@@ -144,12 +144,12 @@ afterEach(() => {
describe('Block', () => { describe('Block', () => {
it('renders error state if error is present', async () => { it('renders error state if error is present', async () => {
(useFetch as jest.Mock).mockReturnValue({ (useFetch as jest.Mock).mockReturnValue({
state: { data: null, loading: false, error: new Error('asd') }, state: { data: null, loading: false, error: 'asd' },
}); });
render(renderComponent()); render(renderComponent());
expect(screen.getByText(`BLOCK ${blockId}`)).toBeInTheDocument(); expect(screen.getByText(`BLOCK ${blockId}`)).toBeInTheDocument();
expect(screen.getByText('Something went wrong: asd')).toBeInTheDocument(); expect(screen.getByText('Error retrieving data')).toBeInTheDocument();
}); });
it('renders loading state if present', async () => { it('renders loading state if present', async () => {
@@ -1,3 +1,4 @@
import React from 'react';
import { Link, useParams } from 'react-router-dom'; import { Link, useParams } from 'react-router-dom';
import { DATA_SOURCES } from '../../../config'; import { DATA_SOURCES } from '../../../config';
import { getDateTimeFormat } from '@vegaprotocol/utils'; import { getDateTimeFormat } from '@vegaprotocol/utils';
@@ -11,8 +12,9 @@ import {
TableCell, TableCell,
} from '../../../components/table'; } from '../../../components/table';
import { TxsPerBlock } from '../../../components/txs/txs-per-block'; import { TxsPerBlock } from '../../../components/txs/txs-per-block';
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit'; import { Button } from '@vegaprotocol/ui-toolkit';
import { Routes } from '../../route-names'; import { Routes } from '../../route-names';
import { RenderFetched } from '../../../components/render-fetched';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useFetch } from '@vegaprotocol/react-helpers'; import { useFetch } from '@vegaprotocol/react-helpers';
import { NodeLink } from '../../../components/links'; import { NodeLink } from '../../../components/links';
@@ -32,7 +34,7 @@ const Block = () => {
return ( return (
<section> <section>
<RouteTitle data-testid="block-header">{t(`BLOCK ${block}`)}</RouteTitle> <RouteTitle data-testid="block-header">{t(`BLOCK ${block}`)}</RouteTitle>
<AsyncRenderer data={blockData} error={error} loading={!!loading}> <RenderFetched error={error} loading={loading}>
<> <>
<div className="grid grid-cols-2 gap-2 mb-8"> <div className="grid grid-cols-2 gap-2 mb-8">
<Link <Link
@@ -121,7 +123,7 @@ const Block = () => {
</> </>
)} )}
</> </>
</AsyncRenderer> </RenderFetched>
</section> </section>
); );
}; };
+11 -16
View File
@@ -1,7 +1,7 @@
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useFetch } from '@vegaprotocol/react-helpers'; import { useFetch } from '@vegaprotocol/react-helpers';
import { RouteTitle } from '../../components/route-title'; import { RouteTitle } from '../../components/route-title';
import { AsyncRenderer, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit'; import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { DATA_SOURCES } from '../../config'; import { DATA_SOURCES } from '../../config';
import type { TendermintGenesisResponse } from './tendermint-genesis-response'; import type { TendermintGenesisResponse } from './tendermint-genesis-response';
import { useDocumentTitle } from '../../hooks/use-document-title'; import { useDocumentTitle } from '../../hooks/use-document-title';
@@ -10,26 +10,21 @@ const Genesis = () => {
useDocumentTitle(['Genesis']); useDocumentTitle(['Genesis']);
const { const {
state: { data, loading, error }, state: { data: genesis, loading },
} = useFetch<TendermintGenesisResponse>( } = useFetch<TendermintGenesisResponse>(
`${DATA_SOURCES.tendermintUrl}/genesis` `${DATA_SOURCES.tendermintUrl}/genesis`
); );
if (!genesis?.result.genesis) {
if (loading) {
return <Loader />;
}
return null;
}
return ( return (
<> <section>
<RouteTitle data-testid="genesis-header">{t('Genesis')}</RouteTitle> <RouteTitle data-testid="genesis-header">{t('Genesis')}</RouteTitle>
<AsyncRenderer <SyntaxHighlighter data={genesis?.result.genesis} />
data={data} </section>
error={error}
loading={!!loading}
loadingMessage={t('Loading genesis information...')}
errorMessage={t('Could not fetch genesis data')}
>
<section>
<SyntaxHighlighter data={data?.result.genesis} />
</section>
</AsyncRenderer>
</>
); );
}; };
@@ -1,6 +1,6 @@
import { proposalsDataProvider } from '@vegaprotocol/proposals'; import { proposalsDataProvider } from '@vegaprotocol/proposals';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/data-provider'; import { useDataProvider } from '@vegaprotocol/react-helpers';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { ProposalsTable } from '../../components/proposals/proposals-table'; import { ProposalsTable } from '../../components/proposals/proposals-table';
import { RouteTitle } from '../../components/route-title'; import { RouteTitle } from '../../components/route-title';
@@ -1,5 +1,5 @@
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/data-provider'; import { useDataProvider } from '@vegaprotocol/react-helpers';
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit'; import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
import { useState } from 'react'; import { useState } from 'react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
@@ -49,7 +49,6 @@ export const MarketPage = () => {
/> />
<AsyncRenderer <AsyncRenderer
noDataMessage={t('This chain has no markets')} noDataMessage={t('This chain has no markets')}
errorMessage={t('Could not fetch market') + ' ' + marketId}
data={data} data={data}
loading={loading} loading={loading}
error={error} error={error}
@@ -4,7 +4,7 @@ import { marketsProvider } from '@vegaprotocol/market-list';
import { RouteTitle } from '../../components/route-title'; import { RouteTitle } from '../../components/route-title';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/data-provider'; import { useDataProvider } from '@vegaprotocol/react-helpers';
import { MarketsTable } from '../../components/markets/markets-table'; import { MarketsTable } from '../../components/markets/markets-table';
export const MarketsPage = () => { export const MarketsPage = () => {
@@ -1,5 +1,5 @@
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters'; import type { NetworkParamsQuery } from '@vegaprotocol/react-helpers';
import { NetworkParametersTable } from './network-parameters'; import { NetworkParametersTable } from './network-parameters';
describe('NetworkParametersTable', () => { describe('NetworkParametersTable', () => {
@@ -13,15 +13,14 @@ import {
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { RouteTitle } from '../../components/route-title'; import { RouteTitle } from '../../components/route-title';
import orderBy from 'lodash/orderBy'; import orderBy from 'lodash/orderBy';
import { useNetworkParamsQuery } from '@vegaprotocol/network-parameters'; import { useNetworkParamsQuery } from '@vegaprotocol/react-helpers';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters'; import type { NetworkParamsQuery } from '@vegaprotocol/react-helpers';
import { useScrollToLocation } from '../../hooks/scroll-to-location'; import { useScrollToLocation } from '../../hooks/scroll-to-location';
import { useDocumentTitle } from '../../hooks/use-document-title'; import { useDocumentTitle } from '../../hooks/use-document-title';
const PERCENTAGE_PARAMS = [ const PERCENTAGE_PARAMS = [
'governance.proposal.asset.requiredMajority', 'governance.proposal.asset.requiredMajority',
'governance.proposal.asset.requiredParticipation', 'governance.proposal.asset.requiredParticipation',
'governance.proposal.updateAsset.requiredParticipation',
'governance.proposal.freeform.requiredMajority', 'governance.proposal.freeform.requiredMajority',
'governance.proposal.freeform.requiredParticipation', 'governance.proposal.freeform.requiredParticipation',
'governance.proposal.market.requiredMajority', 'governance.proposal.market.requiredMajority',
@@ -54,8 +53,6 @@ const BIG_NUMBER_PARAMS = [
'governance.proposal.asset.minProposerBalance', 'governance.proposal.asset.minProposerBalance',
'governance.proposal.market.minProposerBalance', 'governance.proposal.market.minProposerBalance',
'governance.proposal.market.minVoterBalance', 'governance.proposal.market.minVoterBalance',
'governance.proposal.updateAsset.minProposerBalance',
'governance.proposal.updateAsset.minVoterBalance',
]; ];
export const NetworkParameterRow = ({ export const NetworkParameterRow = ({
@@ -1,4 +1,4 @@
import { AsyncRenderer, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit'; import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { RouteTitle } from '../../../components/route-title'; import { RouteTitle } from '../../../components/route-title';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useExplorerOracleSpecsQuery } from '../__generated__/Oracles'; import { useExplorerOracleSpecsQuery } from '../__generated__/Oracles';
@@ -8,7 +8,7 @@ import { useScrollToLocation } from '../../../hooks/scroll-to-location';
import filter from 'recursive-key-filter'; import filter from 'recursive-key-filter';
const Oracles = () => { const Oracles = () => {
const { data, loading, error } = useExplorerOracleSpecsQuery(); const { data, loading } = useExplorerOracleSpecsQuery();
useDocumentTitle(['Oracles']); useDocumentTitle(['Oracles']);
useScrollToLocation(); useScrollToLocation();
@@ -16,40 +16,28 @@ const Oracles = () => {
return ( return (
<section> <section>
<RouteTitle data-testid="oracle-specs-heading">{t('Oracles')}</RouteTitle> <RouteTitle data-testid="oracle-specs-heading">{t('Oracles')}</RouteTitle>
<AsyncRenderer {loading ? <Loader /> : null}
data={data} {data?.oracleSpecsConnection?.edges
loading={loading} ? data.oracleSpecsConnection.edges.map((o) => {
error={error} const id = o?.node.dataSourceSpec.spec.id;
loadingMessage={t('Loading oracle data...')} if (!id) {
errorMessage={t('Oracle data could not be loaded')} return null;
noDataMessage={t('No oracles found')} }
noDataCondition={(data) => return (
!data?.oracleSpecsConnection?.edges || <div id={id} key={id} className="mb-10">
data.oracleSpecsConnection.edges?.length === 0 <OracleDetails
} id={id}
> dataSource={o?.node}
{data?.oracleSpecsConnection?.edges showBroadcasts={false}
? data.oracleSpecsConnection.edges.map((o) => { />
const id = o?.node.dataSourceSpec.spec.id; <details>
if (!id) { <summary className="pointer">JSON</summary>
return null; <SyntaxHighlighter data={filter(o, ['__typename'])} />
} </details>
return ( </div>
<div id={id} key={id} className="mb-10"> );
<OracleDetails })
id={id} : null}
dataSource={o?.node}
showBroadcasts={false}
/>
<details>
<summary className="pointer">JSON</summary>
<SyntaxHighlighter data={filter(o, ['__typename'])} />
</details>
</div>
);
})
: null}
</AsyncRenderer>
</section> </section>
); );
}; };
@@ -1,11 +1,12 @@
import { RouteTitle } from '../../../components/route-title'; import { RouteTitle } from '../../../components/route-title';
import { RenderFetched } from '../../../components/render-fetched';
import { truncateByChars } from '@vegaprotocol/utils'; import { truncateByChars } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useDocumentTitle } from '../../../hooks/use-document-title'; import { useDocumentTitle } from '../../../hooks/use-document-title';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { useExplorerOracleSpecByIdQuery } from '../__generated__/Oracles'; import { useExplorerOracleSpecByIdQuery } from '../__generated__/Oracles';
import { OracleDetails } from '../components/oracle'; import { OracleDetails } from '../components/oracle';
import { AsyncRenderer, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit'; import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import filter from 'recursive-key-filter'; import filter from 'recursive-key-filter';
import { TruncateInline } from '../../../components/truncate/truncate'; import { TruncateInline } from '../../../components/truncate/truncate';
@@ -26,14 +27,7 @@ export const Oracle = () => {
{t(`Oracle `)} {t(`Oracle `)}
<TruncateInline startChars={5} endChars={5} text={id || '1'} /> <TruncateInline startChars={5} endChars={5} text={id || '1'} />
</RouteTitle> </RouteTitle>
<AsyncRenderer <RenderFetched error={error} loading={loading}>
data={data}
error={error}
loading={loading}
noDataCondition={(data) => !data?.oracleSpec}
errorMessage={t('Could not load oracle data')}
loadingMessage={t('Loading oracle data...')}
>
{data?.oracleSpec ? ( {data?.oracleSpec ? (
<div id={id} key={id} className="mb-10"> <div id={id} key={id} className="mb-10">
<OracleDetails <OracleDetails
@@ -50,7 +44,7 @@ export const Oracle = () => {
) : ( ) : (
<span></span> <span></span>
)} )}
</AsyncRenderer> </RenderFetched>
</section> </section>
); );
}; };
@@ -48,13 +48,6 @@ query ExplorerPartyAssets($partyId: ID!) {
} }
stakingSummary { stakingSummary {
currentStakeAvailable currentStakeAvailable
linkings(pagination: { first: 100 }) {
edges {
node {
amount
}
}
}
} }
accountsConnection { accountsConnection {
edges { edges {
@@ -10,7 +10,7 @@ export type ExplorerPartyAssetsQueryVariables = Types.Exact<{
}>; }>;
export type ExplorerPartyAssetsQuery = { __typename?: 'Query', partiesConnection?: { __typename?: 'PartyConnection', edges: Array<{ __typename?: 'PartyEdge', node: { __typename?: 'Party', id: string, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } } } | null> | null } | null, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string, linkings: { __typename?: 'StakesConnection', edges?: Array<{ __typename?: 'StakeLinkingEdge', node: { __typename?: 'StakeLinking', amount: string } } | null> | null } }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } | null } } | null> | null } | null } }> } | null }; export type ExplorerPartyAssetsQuery = { __typename?: 'Query', partiesConnection?: { __typename?: 'PartyConnection', edges: Array<{ __typename?: 'PartyEdge', node: { __typename?: 'Party', id: string, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } } } | null> | null } | null, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } | null } } | null> | null } | null } }> } | null };
export const ExplorerPartyAssetsAccountsFragmentDoc = gql` export const ExplorerPartyAssetsAccountsFragmentDoc = gql`
fragment ExplorerPartyAssetsAccounts on AccountBalance { fragment ExplorerPartyAssetsAccounts on AccountBalance {
@@ -64,13 +64,6 @@ export const ExplorerPartyAssetsDocument = gql`
} }
stakingSummary { stakingSummary {
currentStakeAvailable currentStakeAvailable
linkings(pagination: {first: 100}) {
edges {
node {
amount
}
}
}
} }
accountsConnection { accountsConnection {
edges { edges {
@@ -1,24 +0,0 @@
import { t } from '@vegaprotocol/i18n';
import { useParams } from 'react-router-dom';
import { toNonHex } from '../../../../components/search/detect-search';
import { PageHeader } from '../../../../components/page-header';
import { useDocumentTitle } from '../../../../hooks/use-document-title';
import { PartyAccounts } from '../components/party-accounts';
const PartyAccountsByAsset = () => {
const { party } = useParams<{ party: string }>();
useDocumentTitle(['Public keys', party || '-']);
const partyId = toNonHex(party ? party : '');
return (
<section>
<PageHeader title={t('Balances by asset')} />
<PartyAccounts partyId={partyId} />
</section>
);
};
export { PartyAccountsByAsset };
@@ -1,9 +1,32 @@
import { AccountManager } from '@vegaprotocol/accounts'; import { t } from '@vegaprotocol/i18n';
import { useCallback } from 'react'; import get from 'lodash/get';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; import AssetBalance from '../../../../components/asset-balance/asset-balance';
import { AssetLink, MarketLink } from '../../../../components/links';
import { Table, TableRow } from '../../../../components/table';
import type * as Schema from '@vegaprotocol/types';
import type { ExplorerPartyAssetsAccountsFragment } from '../__generated__/Party-assets';
const accountTypeString: Record<Schema.AccountType, string> = {
ACCOUNT_TYPE_BOND: t('Bond'),
ACCOUNT_TYPE_EXTERNAL: t('External'),
ACCOUNT_TYPE_FEES_INFRASTRUCTURE: t('Fees (Infrastructure)'),
ACCOUNT_TYPE_FEES_LIQUIDITY: t('Fees (Liquidity)'),
ACCOUNT_TYPE_FEES_MAKER: t('Fees (Maker)'),
ACCOUNT_TYPE_GENERAL: t('General'),
ACCOUNT_TYPE_GLOBAL_INSURANCE: t('Global Insurance Pool'),
ACCOUNT_TYPE_GLOBAL_REWARD: t('Global Reward Pool'),
ACCOUNT_TYPE_INSURANCE: t('Insurance'),
ACCOUNT_TYPE_MARGIN: t('Margin'),
ACCOUNT_TYPE_PENDING_TRANSFERS: t('Pending Transfers'),
ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: t('Reward - LP Fees received'),
ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: t('Reward - Maker fees paid'),
ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: t('Reward - Maker fees received'),
ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: t('Reward - Market proposers'),
ACCOUNT_TYPE_SETTLEMENT: t('Settlement'),
};
interface PartyAccountsProps { interface PartyAccountsProps {
partyId: string; accounts: ExplorerPartyAssetsAccountsFragment[];
} }
/** /**
@@ -11,22 +34,49 @@ interface PartyAccountsProps {
* probably do with sorting by asset, and then within asset, by type with general * probably do with sorting by asset, and then within asset, by type with general
* appearing first and... tbd * appearing first and... tbd
*/ */
export const PartyAccounts = ({ partyId }: PartyAccountsProps) => { export const PartyAccounts = ({ accounts }: PartyAccountsProps) => {
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
const onClickAsset = useCallback(
(assetId?: string) => {
assetId && openAssetDetailsDialog(assetId);
},
[openAssetDetailsDialog]
);
return ( return (
<div className="block min-h-44 h-60 4 w-full border-red-800 relative"> <Table className="max-w-5xl min-w-fit">
<AccountManager <thead>
partyId={partyId} <TableRow modifier="bordered" className="font-mono">
onClickAsset={onClickAsset} <td>{t('Type')}</td>
isReadOnly={true} <td>{t('Market')}</td>
/> <td className="text-right pr-2">{t('Balance')}</td>
</div> <td>{t('Asset')}</td>
</TableRow>
</thead>
<tbody>
{accounts.map((account) => {
const m = get(account, 'market.tradableInstrument.instrument.name');
return (
<TableRow
key={`pa-${account.asset.id}-${account.type}`}
title={account.asset.name}
id={`${accountTypeString[account.type]} ${m ? ` - ${m}` : ''}`}
>
<td className="text-md">{accountTypeString[account.type]}</td>
<td className="text-md">
{account.market?.id ? (
<MarketLink id={account.market?.id} />
) : (
<p>-</p>
)}
</td>
<td className="text-md text-right pr-2">
<AssetBalance
assetId={account.asset.id}
price={account.balance}
showAssetLink={false}
/>
</td>
<td className="text-md">
<AssetLink assetId={account.asset.id} />
</td>
</TableRow>
);
})}
</tbody>
</Table>
); );
}; };
@@ -1,63 +0,0 @@
import { t } from '@vegaprotocol/i18n';
import { useNavigate } from 'react-router-dom';
import { Routes } from '../../../../routes/route-names';
import { Button, Icon, Loader } from '@vegaprotocol/ui-toolkit';
import { PartyBlock } from './party-block';
import type { AccountFields } from '@vegaprotocol/accounts';
export interface PartyBlockAccountProps {
partyId: string;
accountData: AccountFields[] | null;
accountLoading: boolean;
accountError?: Error;
}
/**
* Displays an overview of a party's assets. This uses existing data
* providers to structure the details by asset, rather than looking at
* it by account. The assumption is that this is a more natural way to
* get an idea of the assets and activity of a party.
*/
export const PartyBlockAccounts = ({
partyId,
accountData,
accountLoading,
accountError,
}: PartyBlockAccountProps) => {
const navigate = useNavigate();
const shouldShowActionButton =
accountData && accountData.length > 0 && !accountLoading && !accountError;
const action = shouldShowActionButton ? (
<Button
size="sm"
onClick={() => navigate(`/${Routes.PARTIES}/${partyId}/assets`)}
>
{t('Show all')}
</Button>
) : null;
return (
<PartyBlock title={t('Assets')} action={action}>
{accountData && accountData.length > 0 ? (
<p>
{accountData.length} {t('assets, including')}{' '}
{accountData
.map((a) => a.asset.symbol)
.slice(0, 3)
.join(', ')}
</p>
) : accountLoading && !accountError ? (
<Loader size="small" />
) : accountData && accountData.length === 0 ? (
<p>{t('No accounts found')}</p>
) : (
<p>
<Icon className="mr-1" name="error" />
<span className="text-sm">{t('Could not load assets')}</span>
</p>
)}
</PartyBlock>
);
};
@@ -1,83 +0,0 @@
import { t } from '@vegaprotocol/i18n';
import { useExplorerPartyAssetsQuery } from '../__generated__/Party-assets';
import GovernanceAssetBalance from '../../../../components/asset-balance/governance-asset-balance';
import {
Icon,
KeyValueTable,
KeyValueTableRow,
Loader,
} from '@vegaprotocol/ui-toolkit';
import { PartyBlock } from './party-block';
import BigNumber from 'bignumber.js';
export interface PartyBlockStakeProps {
partyId: string;
accountLoading: boolean;
accountError?: Error;
}
/**
* Displays an overview of a single party's staking balance, importantly maintaining'
* the same height before and after the details are loaded in.
*
* Unlike PartyBlockAccounts there is not action button in the title of this block as
* there is no page for it to link to currently. That's a future task.
*/
export const PartyBlockStake = ({
partyId,
accountLoading,
accountError,
}: PartyBlockStakeProps) => {
const partyRes = useExplorerPartyAssetsQuery({
// Don't cache data for this query, party information can move quite quickly
fetchPolicy: 'network-only',
variables: { partyId: partyId },
skip: !partyId,
});
const p = partyRes.data?.partiesConnection?.edges[0].node;
const linkedLength = p?.stakingSummary?.linkings?.edges?.length;
const linkedStake =
linkedLength && linkedLength > 0
? p?.stakingSummary?.linkings?.edges
?.reduce((total, e) => {
return new BigNumber(total).plus(
new BigNumber(e?.node.amount || 0)
);
}, new BigNumber(0))
.toString()
: '0';
return (
<PartyBlock title={t('Staking')}>
{p?.stakingSummary.currentStakeAvailable ? (
<KeyValueTable>
<KeyValueTableRow noBorder={true}>
<div>{t('Available stake')}</div>
<div>
<GovernanceAssetBalance
price={p.stakingSummary.currentStakeAvailable}
/>
</div>
</KeyValueTableRow>
<KeyValueTableRow noBorder={true}>
<div>{t('Active stake')}</div>
<div>
<GovernanceAssetBalance price={linkedStake || '0'} />
</div>
</KeyValueTableRow>
</KeyValueTable>
) : accountLoading && !accountError ? (
<Loader size="small" />
) : !accountError ? (
<p>{t('No staking balance')}</p>
) : (
<p>
<Icon className="mr-1" name="error" />
<span className="text-sm">{t('Could not load stake details')}</span>
</p>
)}
</PartyBlock>
);
};
@@ -1,24 +0,0 @@
import type { ReactNode } from 'react';
export interface PartyBlockProps {
children: ReactNode;
title: string;
action?: ReactNode;
}
export function PartyBlock({ children, title, action }: PartyBlockProps) {
return (
<div className="border-2 min-h-[138px] border-solid border-vega-light-100 dark:border-vega-dark-200 p-5 mt-5">
<div
className="flex flex-col md:flex-row gap-1 justify-between content-start mb-2"
data-testid="page-title"
>
<h3 className="font-semibold text-lg">{title}</h3>
{action ? action : null}
</div>
{children}
</div>
);
}
@@ -1,26 +1,24 @@
import { getNodes } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useScreenDimensions } from '@vegaprotocol/react-helpers'; import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useNavigate, useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { SubHeading } from '../../../components/sub-heading'; import { SubHeading } from '../../../components/sub-heading';
import { Panel } from '../../../components/panel';
import { toNonHex } from '../../../components/search/detect-search'; import { toNonHex } from '../../../components/search/detect-search';
import { useTxsData } from '../../../hooks/use-txs-data'; import { useTxsData } from '../../../hooks/use-txs-data';
import { TxsInfiniteList } from '../../../components/txs'; import { TxsInfiniteList } from '../../../components/txs';
import { PageHeader } from '../../../components/page-header'; import { PageHeader } from '../../../components/page-header';
import { useExplorerPartyAssetsQuery } from './__generated__/Party-assets';
import type { ExplorerPartyAssetsAccountsFragment } from './__generated__/Party-assets';
import { useDocumentTitle } from '../../../hooks/use-document-title'; import { useDocumentTitle } from '../../../hooks/use-document-title';
import { Icon, Intent, Notification, Splash } from '@vegaprotocol/ui-toolkit'; import GovernanceAssetBalance from '../../../components/asset-balance/governance-asset-balance';
import { aggregatedAccountsDataProvider } from '@vegaprotocol/accounts'; import { PartyAccounts } from './components/party-accounts';
import { PartyBlockStake } from './components/party-block-stake';
import { PartyBlockAccounts } from './components/party-block-accounts';
import { isValidPartyId } from './components/party-id-error';
import { useDataProvider } from '@vegaprotocol/data-provider';
const Party = () => { const Party = () => {
const { party } = useParams<{ party: string }>(); const { party } = useParams<{ party: string }>();
useDocumentTitle(['Public keys', party || '-']); useDocumentTitle(['Public keys', party || '-']);
const navigate = useNavigate();
const partyId = toNonHex(party ? party : ''); const partyId = toNonHex(party ? party : '');
const { isMobile } = useScreenDimensions(); const { isMobile } = useScreenDimensions();
const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]); const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]);
@@ -30,72 +28,71 @@ const Party = () => {
filters, filters,
}); });
const variables = useMemo(() => ({ partyId }), [partyId]); const partyRes = useExplorerPartyAssetsQuery({
const { // Don't cache data for this query, party information can move quite quickly
data: AccountData, fetchPolicy: 'network-only',
loading: AccountLoading, variables: { partyId: partyId },
error: AccountError, skip: !party,
} = useDataProvider({
dataProvider: aggregatedAccountsDataProvider,
variables,
}); });
if (!isValidPartyId(partyId)) { const p = partyRes.data?.partiesConnection?.edges[0].node;
return (
<div className="max-w-sm mx-auto"> const header = p?.id ? (
<Notification <PageHeader
message={t('Invalid party ID')} title={p.id}
intent={Intent.Danger} copy
buttonProps={{ truncateStart={visibleChars}
text: t('Go back'), truncateEnd={visibleChars}
action: () => navigate(-1), />
className: 'py-1', ) : (
size: 'sm', <Panel>
}} <p>No data found for public key {party}</p>
/> </Panel>
</div> );
);
} const staking = (
<section>
{p?.stakingSummary?.currentStakeAvailable ? (
<div className="mt-4 leading-3">
<strong className="font-semibold">{t('Staking Balance: ')}</strong>
<GovernanceAssetBalance
price={p.stakingSummary.currentStakeAvailable}
/>
</div>
) : null}
</section>
);
const accounts = getNodes<ExplorerPartyAssetsAccountsFragment>(
p?.accountsConnection
);
return ( return (
<section> <section>
<PageHeader <h1
title={partyId} className="font-alpha calt uppercase font-xl mb-4 text-vega-dark-100 dark:text-vega-light-100"
copy data-testid="parties-header"
truncateStart={visibleChars} >
truncateEnd={visibleChars} {t('Public key')}
/> </h1>
{partyRes.data ? (
<>
{header}
<SubHeading>{t('Asset data')}</SubHeading>
{accounts ? <PartyAccounts accounts={accounts} /> : null}
{staking}
<div className="grid md:grid-flow-col grid-flow-row md:space-x-4 grid-cols-1 md:grid-cols-2 w-full"> <SubHeading>{t('Transactions')}</SubHeading>
<PartyBlockAccounts <TxsInfiniteList
accountError={AccountError} hasMoreTxs={hasMoreTxs}
accountLoading={AccountLoading} areTxsLoading={loading}
accountData={AccountData} txs={txsData}
partyId={partyId} loadMoreTxs={loadTxs}
/> error={error}
<PartyBlockStake className="mb-28"
accountError={AccountError} />
accountLoading={AccountLoading} </>
partyId={partyId} ) : null}
/>
</div>
<SubHeading>{t('Transactions')}</SubHeading>
{!error && txsData ? (
<TxsInfiniteList
hasMoreTxs={hasMoreTxs}
areTxsLoading={loading}
txs={txsData}
loadMoreTxs={loadTxs}
error={error}
className="mb-28"
/>
) : (
<Splash>
<Icon name="error" className="mr-1" />
&nbsp;{t('Could not load transaction list for party')}
</Splash>
)}
</section> </section>
); );
}; };
@@ -1,7 +0,0 @@
import { Outlet } from 'react-router-dom';
const PartiesSubPage = () => {
return <Outlet />;
};
export default PartiesSubPage;
@@ -0,0 +1,35 @@
import React from 'react';
import { DATA_SOURCES } from '../../config';
import type { TendermintUnconfirmedTransactionsResponse } from '../txs/tendermint-unconfirmed-transactions-response.d';
import { TxList } from '../../components/txs';
import { RouteTitle } from '../../components/route-title';
import { t } from '@vegaprotocol/i18n';
import { useFetch } from '@vegaprotocol/react-helpers';
import { useDocumentTitle } from '../../hooks/use-document-title';
const PendingTxs = () => {
const {
state: { data: unconfirmedTransactions },
} = useFetch<TendermintUnconfirmedTransactionsResponse>(
`${DATA_SOURCES.tendermintUrl}/unconfirmed_txs`
);
useDocumentTitle(['Pending transactions']);
return (
<section>
<RouteTitle data-testid="unconfirmed-transactions-header">
{t('Unconfirmed transactions')}
</RouteTitle>
<br />
<div>{t(`Number: ${unconfirmedTransactions?.result?.n_txs || 0}`)}</div>
<br />
<div>
<br />
<TxList data={unconfirmedTransactions} />
</div>
</section>
);
};
export { PendingTxs };
+20 -38
View File
@@ -14,6 +14,7 @@ import { Block } from './blocks/id';
import { Blocks } from './blocks/home'; import { Blocks } from './blocks/home';
import { Tx } from './txs/id'; import { Tx } from './txs/id';
import { TxsList } from './txs/home'; import { TxsList } from './txs/home';
import { PendingTxs } from './pending';
import flags from '../config/flags'; import flags from '../config/flags';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { Routes } from './route-names'; import { Routes } from './route-names';
@@ -28,7 +29,6 @@ import compact from 'lodash/compact';
import { AssetLink, MarketLink } from '../components/links'; import { AssetLink, MarketLink } from '../components/links';
import { truncateMiddle } from '@vegaprotocol/ui-toolkit'; import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
import { remove0x } from '@vegaprotocol/utils'; import { remove0x } from '@vegaprotocol/utils';
import { PartyAccountsByAsset } from './parties/id/accounts';
export type Navigable = { export type Navigable = {
path: string; path: string;
@@ -75,43 +75,14 @@ const partiesRoutes: Route[] = flags.parties
}, },
{ {
path: ':party', path: ':party',
element: <Party />, element: <PartySingle />,
handle: {
children: [ breadcrumb: (params: Params<string>) => (
{ <Link to={linkTo(Routes.PARTIES, params.party)}>
index: true, {truncateMiddle(params.party as string)}
element: <PartySingle />, </Link>
handle: { ),
breadcrumb: (params: Params<string>) => ( },
<Link to={linkTo(Routes.PARTIES, params.party)}>
{truncateMiddle(params.party as string)}
</Link>
),
},
},
{
path: 'assets',
element: <Party />,
handle: {
breadcrumb: (params: Params<string>) => (
<Link to={linkTo(Routes.PARTIES, params.party)}>
{truncateMiddle(params.party as string)}
</Link>
),
},
children: [
{
index: true,
element: <PartyAccountsByAsset />,
handle: {
breadcrumb: () => {
return t('Assets');
},
},
},
],
},
],
}, },
], ],
}, },
@@ -266,6 +237,17 @@ export const routerConfig: Route[] = [
breadcrumb: () => <Link to={Routes.TX}>{t('Transactions')}</Link>, breadcrumb: () => <Link to={Routes.TX}>{t('Transactions')}</Link>,
}, },
children: [ children: [
{
path: 'pending',
element: <PendingTxs />,
handle: {
breadcrumb: () => (
<Link to={linkTo(Routes.TX, 'pending')}>
{t('Pending transactions')}
</Link>
),
},
},
{ {
path: ':txHash', path: ':txHash',
element: <Tx />, element: <Tx />,
@@ -10,7 +10,7 @@ interface TxDetailsProps {
export const txDetailsTruncateLength = 30; export const txDetailsTruncateLength = 30;
export const TxDetails = ({ txData, pubKey }: TxDetailsProps) => { export const TxDetails = ({ txData, pubKey, className }: TxDetailsProps) => {
if (!txData) { if (!txData) {
return <>{t('Awaiting Block Explorer transaction details')}</>; return <>{t('Awaiting Block Explorer transaction details')}</>;
} }
@@ -28,7 +28,6 @@ import {
} from '@vegaprotocol/environment'; } from '@vegaprotocol/environment';
import classNames from 'classnames'; import classNames from 'classnames';
import { NodeStatus, NodeStatusMapping } from '@vegaprotocol/types'; import { NodeStatus, NodeStatusMapping } from '@vegaprotocol/types';
import { PartyLink } from '../../components/links';
type RateProps = { type RateProps = {
value: BigNumber | number | undefined; value: BigNumber | number | undefined;
@@ -192,9 +191,7 @@ export const ValidatorsPage = () => {
<KeyValueTable> <KeyValueTable>
<KeyValueTableRow> <KeyValueTableRow>
<div>{t('ID')}</div> <div>{t('ID')}</div>
<div className="break-all text-xs font-mono"> <div className="break-all text-xs">{v.id}</div>
{v.id}
</div>
</KeyValueTableRow> </KeyValueTableRow>
<KeyValueTableRow> <KeyValueTableRow>
<div>{t('Status')}</div> <div>{t('Status')}</div>
@@ -221,14 +218,12 @@ export const ValidatorsPage = () => {
</div> </div>
</KeyValueTableRow> </KeyValueTableRow>
<KeyValueTableRow> <KeyValueTableRow>
<div>{t('Key')}</div> <div>{t('Public key')}</div>
<div className="break-all text-xs"> <div className="break-all text-xs">{v.pubkey}</div>
<PartyLink id={v.pubkey} />
</div>
</KeyValueTableRow> </KeyValueTableRow>
<KeyValueTableRow> <KeyValueTableRow>
<div>{t('Ethereum address')}</div> <div>{t('Ethereum address')}</div>
<div className="break-all text-xs font-mono"> <div className="break-all text-xs">
<EtherscanLink address={v.ethereumAddress} />{' '} <EtherscanLink address={v.ethereumAddress} />{' '}
<CopyWithTooltip text={v.ethereumAddress}> <CopyWithTooltip text={v.ethereumAddress}>
<button title={t('Copy address to clipboard')}> <button title={t('Copy address to clipboard')}>
@@ -239,9 +234,7 @@ export const ValidatorsPage = () => {
</KeyValueTableRow> </KeyValueTableRow>
<KeyValueTableRow> <KeyValueTableRow>
<div>{t('Tendermint public key')}</div> <div>{t('Tendermint public key')}</div>
<div className="break-all text-xs font-mono"> <div className="break-all text-xs">{v.tmPubkey}</div>
{v.tmPubkey}
</div>
</KeyValueTableRow> </KeyValueTableRow>
<KeyValueTableRow> <KeyValueTableRow>
-53
View File
@@ -1,7 +1,3 @@
@import 'ag-grid-community/dist/styles/ag-grid.css';
@import 'ag-grid-community/dist/styles/ag-theme-balham.css';
@import 'ag-grid-community/dist/styles/ag-theme-balham-dark.css';
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@@ -15,52 +11,3 @@
.react-markdown-container a:before { .react-markdown-container a:before {
content: '🔗 '; content: '🔗 ';
} }
/* AG GRID - Do not edit without updating other global stylesheets for each app */
.vega-ag-grid .ag-root-wrapper {
border: solid 0px;
}
.vega-ag-grid .ag-react-container {
overflow: hidden;
text-overflow: ellipsis;
}
.vega-ag-grid .ag-cell,
.vega-ag-grid .ag-full-width-row .ag-cell-wrapper.ag-row-group {
line-height: calc(min(var(--ag-line-height, 26px), 26px) - 4px);
}
.vega-ag-grid .ag-row {
border-width: 1px 0;
border-bottom: 1px solid transparent;
}
/* Light variables */
.ag-theme-balham {
--ag-background-color: theme(colors.white);
--ag-border-color: theme(colors.neutral[300]);
--ag-header-background-color: theme(colors.white);
--ag-odd-row-background-color: theme(colors.white);
--ag-header-column-separator-color: theme(colors.neutral[300]);
--ag-row-border-color: theme(colors.white);
--ag-row-hover-color: theme(colors.neutral[100]);
--ag-font-size: 12px;
}
/* Dark variables */
.ag-theme-balham-dark {
--ag-background-color: theme(colors.black);
--ag-border-color: theme(colors.neutral[700]);
--ag-header-background-color: theme(colors.black);
--ag-odd-row-background-color: theme(colors.black);
--ag-header-column-separator-color: theme(colors.neutral[600]);
--ag-row-border-color: theme(colors.black);
--ag-row-hover-color: theme(colors.neutral[800]);
--ag-font-size: 12px;
}
.voteicon svg {
vertical-align: baseline;
}
+5 -4
View File
@@ -5,7 +5,7 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_FAIRGROUND=false NX_FAIRGROUND=false
NX_VEGA_NETWORKS={} NX_VEGA_NETWORKS={}
NX_VEGA_URL=http://localhost:3008/graphql NX_VEGA_URL=http://localhost:3028/query
NX_ETHEREUM_CHAIN_ID=1440 NX_ETHEREUM_CHAIN_ID=1440
NX_ETH_URL_CONNECT=1 NX_ETH_URL_CONNECT=1
NX_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session NX_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
@@ -13,14 +13,14 @@ NX_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/ NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_VEGA_WALLET_URL=http://localhost:1789 NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72 NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
#Test configuration variables #Test configuration variables
CYPRESS_FAIRGROUND=false CYPRESS_FAIRGROUND=false
CYPRESS_VEGA_URL=http://localhost:3008/graphql CYPRESS_VEGA_URL=http://localhost:3028/query
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
CYPRESS_ETHEREUM_PROVIDER_URL=http://localhost:8545 CYPRESS_ETHEREUM_PROVIDER_URL=http://localhost:8545
CYPRESS_EXPLORER_URL=https://explorer.fairground.wtf CYPRESS_EXPLORER_URL=https://explorer.fairground.wtf
@@ -30,6 +30,7 @@ CYPRESS_TRUNCATED_VEGA_PUBLIC_KEY2=7f9cf0…c25535
CYPRESS_VEGA_ENV=CUSTOM CYPRESS_VEGA_ENV=CUSTOM
CYPRESS_VEGA_PUBLIC_KEY=02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65 CYPRESS_VEGA_PUBLIC_KEY=02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65
CYPRESS_VEGA_PUBLIC_KEY2=7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535 CYPRESS_VEGA_PUBLIC_KEY2=7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535
CYPRESS_VEGA_TOKEN_URL=https://governance.fairground.wtf CYPRESS_VEGA_TOKEN_URL=https://token.fairground.wtf
CYPRESS_VEGA_URL=http://localhost:3028/query
CYPRESS_VEGA_WALLET_URL=http://localhost:1789 CYPRESS_VEGA_WALLET_URL=http://localhost:1789
CYPRESS_VEGA_WALLET_API_TOKEN= CYPRESS_VEGA_WALLET_API_TOKEN=
+1 -1
View File
@@ -1,5 +1,5 @@
# App configuration variables # App configuration variables
NX_VEGA_ENV=MAINNET NX_VEGA_ENV=MAINNET
NX_VEGA_URL=https://api.vega.community/graphql NX_VEGA_URL=https://api.vega.xyz/query
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://etherscan.io NX_ETHERSCAN_URL=https://etherscan.io
+5
View File
@@ -0,0 +1,5 @@
# App configuration variables
NX_VEGA_ENV=STAGNET3
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
+1 -1
View File
@@ -1,5 +1,5 @@
# App configuration variables # App configuration variables
NX_VEGA_ENV=TESTNET NX_VEGA_ENV=TESTNET
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_ETHERSCAN_URL=https://sepolia.etherscan.io
@@ -9,7 +9,7 @@
"name": "Token test market", "name": "Token test market",
"code": "Token.24h", "code": "Token.24h",
"future": { "future": {
"settlementAsset": "73174a6fb1d5802ba0ac7bd7ab79e0a3a4837b262de0a4e80815a55442692bd0", "settlementAsset": "fBTC",
"quoteName": "fBTC", "quoteName": "fBTC",
"dataSourceSpecForSettlementData": { "dataSourceSpecForSettlementData": {
"external": { "external": {
@@ -2,14 +2,14 @@ import {
navigateTo, navigateTo,
waitForSpinner, waitForSpinner,
navigation, navigation,
turnTelemetryOff,
} from '../../support/common.functions'; } from '../../support/common.functions';
import { import {
convertUnixTimestampToDateformat,
createRawProposal, createRawProposal,
createTenDigitUnixTimeStampForSpecifiedDays, createTenDigitUnixTimeStampForSpecifiedDays,
enterUniqueFreeFormProposalBody, enterUniqueFreeFormProposalBody,
generateFreeFormProposalTitle, generateFreeFormProposalTitle,
getDateFormatForSpecifiedDays, getGovernanceProposalDateFormatForSpecifiedDays,
getProposalIdFromList, getProposalIdFromList,
getProposalInformationFromTable, getProposalInformationFromTable,
getSubmittedProposalFromProposalList, getSubmittedProposalFromProposalList,
@@ -23,7 +23,6 @@ import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../../../governan
import { ethereumWalletConnect } from '../../../../governance-e2e/src/support/wallet-eth.functions'; import { ethereumWalletConnect } from '../../../../governance-e2e/src/support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../../../governance-e2e/src/support/wallet-teardown.functions'; import { vegaWalletSetSpecifiedApprovalAmount } from '../../../../governance-e2e/src/support/wallet-teardown.functions';
import type { testFreeformProposal } from '../../support/common-interfaces'; import type { testFreeformProposal } from '../../support/common-interfaces';
import { formatDateWithLocalTimezone } from '@vegaprotocol/utils';
const proposalVoteProgressForPercentage = const proposalVoteProgressForPercentage =
'[data-testid="vote-progress-indicator-percentage-for"]'; '[data-testid="vote-progress-indicator-percentage-for"]';
@@ -50,8 +49,6 @@ describe(
}); });
beforeEach('visit proposals tab', function () { beforeEach('visit proposals tab', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
cy.connectVegaWallet(); cy.connectVegaWallet();
@@ -101,22 +98,20 @@ describe(
getSubmittedProposalFromProposalList(proposalTitle).within(() => getSubmittedProposalFromProposalList(proposalTitle).within(() =>
cy.get(viewProposalButton).click() cy.get(viewProposalButton).click()
); );
cy.wrap( convertUnixTimestampToDateformat(proposalTimeStamp).then(
formatDateWithLocalTimezone(new Date(proposalTimeStamp * 1000)) (closingDate) => {
).then((closingDate) => { getProposalInformationFromTable('Closes on')
getProposalInformationFromTable('Closes on') .contains(closingDate)
.contains(closingDate) .should('be.visible');
.should('be.visible'); }
}); );
cy.wrap( getGovernanceProposalDateFormatForSpecifiedDays(0).then(
formatDateWithLocalTimezone( (proposalDate) => {
new Date(createTenDigitUnixTimeStampForSpecifiedDays(0) * 1000) getProposalInformationFromTable('Proposed on')
) .contains(proposalDate)
).then((proposalDate) => { .should('be.visible');
getProposalInformationFromTable('Proposed on') }
.contains(proposalDate) );
.should('be.visible');
});
}); });
it('Newly created proposal details - shows default status set to fail', function () { it('Newly created proposal details - shows default status set to fail', function () {
@@ -159,16 +154,18 @@ describe(
cy.getByTestId('vote-buttons').contains('against').should('be.visible'); cy.getByTestId('vote-buttons').contains('against').should('be.visible');
cy.getByTestId('vote-buttons').contains('for').should('be.visible'); cy.getByTestId('vote-buttons').contains('for').should('be.visible');
voteForProposal('for'); voteForProposal('for');
getDateFormatForSpecifiedDays(0).then((votedDate) => { getGovernanceProposalDateFormatForSpecifiedDays(0, 'shortMonth').then(
// 3001-VOTE-051 (votedDate) => {
// 3001-VOTE-093 // 3001-VOTE-051
cy.contains('You voted:') // 3001-VOTE-093
.siblings() cy.contains('You voted:')
.contains('For') .siblings()
.siblings() .contains('For')
.contains(votedDate) .siblings()
.should('be.visible'); .contains(votedDate)
}); .should('be.visible');
}
);
cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072 cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072
.contains('100.00%') .contains('100.00%')
.and('be.visible'); .and('be.visible');
@@ -220,9 +217,9 @@ describe(
vegaWalletSetSpecifiedApprovalAmount('1000'); vegaWalletSetSpecifiedApprovalAmount('1000');
createRawProposal(); createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => { cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getSubmittedProposalFromProposalList( getSubmittedProposalFromProposalList(rawProposal.rationale.title)
rawProposal.rationale.title .as('submittedProposal')
).within(() => cy.get(viewProposalButton).click()); .within(() => cy.get(viewProposalButton).click());
}); });
voteForProposal('for'); voteForProposal('for');
// 3001-VOTE-079 // 3001-VOTE-079
@@ -240,9 +237,9 @@ describe(
); );
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => { cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getSubmittedProposalFromProposalList( getSubmittedProposalFromProposalList(rawProposal.rationale.title)
rawProposal.rationale.title .as('submittedProposal')
).within(() => cy.get(viewProposalButton).click()); .within(() => cy.get(viewProposalButton).click());
}); });
cy.get(proposalVoteProgressForPercentage) cy.get(proposalVoteProgressForPercentage)
.contains('100.00%') .contains('100.00%')
@@ -2,7 +2,6 @@
import { import {
navigateTo, navigateTo,
navigation, navigation,
turnTelemetryOff,
waitForSpinner, waitForSpinner,
} from '../../support/common.functions'; } from '../../support/common.functions';
import { import {
@@ -17,7 +16,6 @@ import {
import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions'; import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
const proposalListItem = '[data-testid="proposals-list-item"]';
const closedProposals = '[data-testid="closed-proposals"]'; const closedProposals = '[data-testid="closed-proposals"]';
const proposalStatus = '[data-testid="proposal-status"]'; const proposalStatus = '[data-testid="proposal-status"]';
const viewProposalButton = '[data-testid="view-proposal-btn"]'; const viewProposalButton = '[data-testid="view-proposal-btn"]';
@@ -37,8 +35,6 @@ context(
}); });
beforeEach('visit proposals', function () { beforeEach('visit proposals', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
cy.connectVegaWallet(); cy.connectVegaWallet();
@@ -55,8 +51,7 @@ context(
waitForSpinner(); waitForSpinner();
cy.get(closedProposals).within(() => { cy.get(closedProposals).within(() => {
cy.contains(proposalTitle) cy.contains(proposalTitle)
.parentsUntil(proposalListItem) .parentsUntil('[data-testid="proposals-list-item"]')
.last()
.within(() => { .within(() => {
cy.get(proposalStatus).should('have.text', 'Enacted '); cy.get(proposalStatus).should('have.text', 'Enacted ');
cy.get(viewProposalButton).click(); cy.get(viewProposalButton).click();
@@ -83,8 +78,7 @@ context(
waitForSpinner(); waitForSpinner();
cy.get(openProposals).within(() => { cy.get(openProposals).within(() => {
cy.contains(proposalTitle) cy.contains(proposalTitle)
.parentsUntil(proposalListItem) .parentsUntil('[data-testid="proposals-list-item"]')
.last()
.within(() => cy.get(viewProposalButton).click()); .within(() => cy.get(viewProposalButton).click());
}); });
getProposalInformationFromTable('State') getProposalInformationFromTable('State')
@@ -117,8 +111,7 @@ context(
waitForSpinner(); waitForSpinner();
cy.get(openProposals, { timeout: 6000 }).within(() => { cy.get(openProposals, { timeout: 6000 }).within(() => {
cy.contains(proposalTitle) cy.contains(proposalTitle)
.parentsUntil(proposalListItem) .parentsUntil('[data-testid="proposals-list-item"]')
.last()
.within(() => cy.get(viewProposalButton).click()); .within(() => cy.get(viewProposalButton).click());
}); });
getProposalInformationFromTable('State') getProposalInformationFromTable('State')
@@ -140,8 +133,7 @@ context(
waitForSpinner(); waitForSpinner();
cy.get(openProposals).within(() => { cy.get(openProposals).within(() => {
cy.contains(proposalTitle) cy.contains(proposalTitle)
.parentsUntil(proposalListItem) .parentsUntil('[data-testid="proposals-list-item"]')
.last()
.within(() => cy.get(viewProposalButton).click()); .within(() => cy.get(viewProposalButton).click());
}); });
getProposalInformationFromTable('State') getProposalInformationFromTable('State')
@@ -20,7 +20,6 @@ import {
navigateTo, navigateTo,
navigation, navigation,
closeDialog, closeDialog,
turnTelemetryOff,
} from '../../support/common.functions'; } from '../../support/common.functions';
import { import {
clickOnValidatorFromList, clickOnValidatorFromList,
@@ -85,8 +84,6 @@ context(
}); });
beforeEach('visit governance tab', function () { beforeEach('visit governance tab', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
cy.connectVegaWallet(); cy.connectVegaWallet();
@@ -2,7 +2,6 @@ import {
closeDialog, closeDialog,
navigateTo, navigateTo,
navigation, navigation,
turnTelemetryOff,
waitForSpinner, waitForSpinner,
} from '../../support/common.functions'; } from '../../support/common.functions';
import { import {
@@ -51,8 +50,6 @@ const liquidityVoteStatus = 'liquidity-votes-status';
const tokenVoteStatus = 'token-votes-status'; const tokenVoteStatus = 'token-votes-status';
const proposalTermsSection = 'proposal'; const proposalTermsSection = 'proposal';
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey'); const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
const fUSDCId =
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc';
const epochTimeout = Cypress.env('epochTimeout'); const epochTimeout = Cypress.env('epochTimeout');
const proposalTimeout = { timeout: 14000 }; const proposalTimeout = { timeout: 14000 };
@@ -77,8 +74,6 @@ context(
}); });
beforeEach('visit governance tab', function () { beforeEach('visit governance tab', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
cy.connectVegaWallet(); cy.connectVegaWallet();
@@ -269,7 +264,7 @@ context(
it('Unable to submit update market proposal without minimum amount of tokens', function () { it('Unable to submit update market proposal without minimum amount of tokens', function () {
vegaWalletTeardown(); vegaWalletTeardown();
vegaWalletFaucetAssetsWithoutCheck( vegaWalletFaucetAssetsWithoutCheck(
fUSDCId, 'fUSDC',
'1000000', '1000000',
vegaWalletPublicKey vegaWalletPublicKey
); );
@@ -295,7 +290,7 @@ context(
// 3001-VOTE-092 3004-PMAC-001 // 3001-VOTE-092 3004-PMAC-001
it('Able to submit update market proposal and vote for proposal', function () { it('Able to submit update market proposal and vote for proposal', function () {
vegaWalletFaucetAssetsWithoutCheck( vegaWalletFaucetAssetsWithoutCheck(
fUSDCId, 'fUSDC',
'1000000', '1000000',
vegaWalletPublicKey vegaWalletPublicKey
); );
@@ -307,10 +302,7 @@ context(
cy.get('dd').eq(0).should('have.text', 'Test market 1'); cy.get('dd').eq(0).should('have.text', 'Test market 1');
cy.get('dd').eq(1).should('have.text', 'TEST.24h'); cy.get('dd').eq(1).should('have.text', 'TEST.24h');
cy.get('dd').eq(2).should('not.be.empty'); cy.get('dd').eq(2).should('not.be.empty');
cy.get('dd') cy.get('dd').eq(2).invoke('text').as('EnactedMarketId');
.eq(2)
.invoke('text')
.as('EnactedMarketId', { type: 'static' });
}); });
cy.get('@EnactedMarketId').then((marketId) => { cy.get('@EnactedMarketId').then((marketId) => {
cy.VegaWalletSubmitLiquidityProvision(String(marketId), '1'); cy.VegaWalletSubmitLiquidityProvision(String(marketId), '1');
@@ -328,7 +320,6 @@ context(
cy.get('@EnactedMarketId').then((marketId) => { cy.get('@EnactedMarketId').then((marketId) => {
cy.contains(String(marketId)) cy.contains(String(marketId))
.parentsUntil(proposalListItem) .parentsUntil(proposalListItem)
.last()
.within(() => { .within(() => {
cy.getByTestId(viewProposalBtn).click(); cy.getByTestId(viewProposalBtn).click();
}); });
@@ -382,19 +373,16 @@ context(
cy.get(newProposalSubmitButton).should('be.visible').click(); cy.get(newProposalSubmitButton).should('be.visible').click();
// cannot submit a proposal with ERC20 address already in use // cannot submit a proposal with ERC20 address already in use
cy.contains('Proposal rejected', proposalTimeout).should('be.visible'); cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
cy.getByTestId('dialog-content') cy.getByTestId('dialog-content').within(() => {
.last() cy.get('p').should(
.within(() => { 'have.text',
cy.get('p').should( 'PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE'
'have.text', );
'PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE' });
);
});
closeDialog(); closeDialog();
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
cy.contains(proposalTitle) cy.contains(proposalTitle)
.parentsUntil(proposalListItem) .parentsUntil(proposalListItem)
.last()
.within(() => { .within(() => {
cy.getByTestId(viewProposalBtn).click(); cy.getByTestId(viewProposalBtn).click();
}); });
@@ -432,7 +420,6 @@ context(
cy.get(proposalType) cy.get(proposalType)
.contains('Update asset') .contains('Update asset')
.parentsUntil(proposalListItem) .parentsUntil(proposalListItem)
.last()
.within(() => { .within(() => {
cy.get(proposalDetails).should('contain.text', assetId); // 3001-VOTE-029 cy.get(proposalDetails).should('contain.text', assetId); // 3001-VOTE-029
cy.getByTestId(viewProposalBtn).click(); cy.getByTestId(viewProposalBtn).click();
@@ -2,7 +2,6 @@ import type { testFreeformProposal } from '../../support/common-interfaces';
import { import {
navigateTo, navigateTo,
navigation, navigation,
turnTelemetryOff,
waitForSpinner, waitForSpinner,
} from '../../support/common.functions'; } from '../../support/common.functions';
import { import {
@@ -36,8 +35,6 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
}); });
beforeEach('visit proposals tab', function () { beforeEach('visit proposals tab', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
cy.connectVegaWallet(); cy.connectVegaWallet();
@@ -62,10 +59,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
cy.get(openProposals).within(() => { cy.get(openProposals).within(() => {
cy.get(proposalClosingDate).first().should('contain.text', 'year'); cy.get(proposalClosingDate).first().should('contain.text', 'year');
cy.get(proposalClosingDate).should('contain.text', 'months'); cy.get(proposalClosingDate).should('contain.text', 'months');
cy.get(proposalClosingDate) cy.get(proposalClosingDate).last().should('contain.text', 'days');
.last()
.invoke('text')
.should('match', /days|minutes/);
}); });
}); });
@@ -1,7 +1,6 @@
import { import {
navigateTo, navigateTo,
navigation, navigation,
turnTelemetryOff,
waitForSpinner, waitForSpinner,
} from '../../support/common.functions'; } from '../../support/common.functions';
import { import {
@@ -26,11 +25,9 @@ const rewardsTimeOut = { timeout: 60000 };
context('rewards - flow', { tags: '@slow' }, function () { context('rewards - flow', { tags: '@slow' }, function () {
before('set up environment to allow rewards', function () { before('set up environment to allow rewards', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.visit('/'); cy.visit('/');
waitForSpinner(); waitForSpinner();
depositAsset(vegaAssetAddress, '1000', 18); depositAsset(vegaAssetAddress, '1000');
cy.validatorsSelfDelegate(); cy.validatorsSelfDelegate();
ethereumWalletConnect(); ethereumWalletConnect();
cy.connectVegaWallet(); cy.connectVegaWallet();
@@ -59,7 +56,7 @@ context('rewards - flow', { tags: '@slow' }, function () {
cy.getByTestId(rewardsTable) cy.getByTestId(rewardsTable)
.first() .first()
.within(() => { .within(() => {
cy.getByTestId('asset', rewardsTimeOut).should('have.text', 'Vega'); cy.getByTestId('asset').should('have.text', 'Vega');
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD').should('have.text', '1'); cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD').should('have.text', '1');
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE').should( cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE').should(
'have.text', 'have.text',
@@ -96,13 +93,13 @@ context('rewards - flow', { tags: '@slow' }, function () {
.within(() => { .within(() => {
cy.get('h2').first().should('contain.text', 'EPOCH'); cy.get('h2').first().should('contain.text', 'EPOCH');
cy.getByTestId('individual-rewards-asset').should('have.text', 'Vega'); cy.getByTestId('individual-rewards-asset').should('have.text', 'Vega');
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD', rewardsTimeOut) cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD')
.should('contain.text', '0.4415') .should('contain.text', '0.1177')
.and('contain.text', '(44.15%)'); .and('contain.text', '(11.7733%)');
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE') cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE')
.should('contain.text', '0.0004') .should('contain.text', '0.0001')
.and('contain.text', '(44.15%)'); .and('contain.text', '(11.7733%)');
cy.getByTestId('total').should('have.text', '0.4419'); cy.getByTestId('total').should('have.text', '0.1179');
}); });
}); });
}); });
@@ -7,7 +7,6 @@ import {
waitForSpinner, waitForSpinner,
navigateTo, navigateTo,
navigation, navigation,
turnTelemetryOff,
} from '../../support/common.functions'; } from '../../support/common.functions';
import { import {
clickOnValidatorFromList, clickOnValidatorFromList,
@@ -56,6 +55,7 @@ context(
function () { function () {
// 2001-STKE-002, 2001-STKE-032 // 2001-STKE-002, 2001-STKE-032
before('visit staking tab and connect vega wallet', function () { before('visit staking tab and connect vega wallet', function () {
cy.clearAllLocalStorage();
cy.visit('/'); cy.visit('/');
ethereumWalletConnect(); ethereumWalletConnect();
// this is a workaround for #2422 which can be removed once issue is resolved // this is a workaround for #2422 which can be removed once issue is resolved
@@ -67,8 +67,6 @@ context(
beforeEach( beforeEach(
'teardown wallet & drill into a specific validator', 'teardown wallet & drill into a specific validator',
function () { function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
cy.connectVegaWallet(); cy.connectVegaWallet();
@@ -254,10 +252,10 @@ context(
waitForBeginningOfEpoch(); waitForBeginningOfEpoch();
cy.getByTestId(stakeValidatorListStakePercentage).should( cy.getByTestId(stakeValidatorListStakePercentage).should(
'have.text', 'have.text',
'50.02%' '100%'
); );
navigateTo(navigation.validators); navigateTo(navigation.validators);
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%'); validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
} }
); );
@@ -4,7 +4,6 @@ import {
waitForSpinner, waitForSpinner,
navigateTo, navigateTo,
navigation, navigation,
turnTelemetryOff,
} from '../../support/common.functions'; } from '../../support/common.functions';
import { import {
stakingPageAssociateTokens, stakingPageAssociateTokens,
@@ -54,8 +53,6 @@ context(
beforeEach( beforeEach(
'teardown wallet & drill into a specific validator', 'teardown wallet & drill into a specific validator',
function () { function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
cy.connectVegaWallet(); cy.connectVegaWallet();
@@ -93,14 +90,9 @@ context(
verifyEthWalletTotalAssociatedBalance('2.0'); verifyEthWalletTotalAssociatedBalance('2.0');
cy.get(vegaWallet) cy.get(vegaWallet).within(() => {
.first() cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
.within(() => { });
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0); cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
}); });
@@ -136,38 +128,26 @@ context(
stakingPageAssociateTokens('1001', { approve: true }); stakingPageAssociateTokens('1001', { approve: true });
verifyEthWalletAssociatedBalance('1,001.00'); verifyEthWalletAssociatedBalance('1,001.00');
verifyEthWalletTotalAssociatedBalance('1,001.00'); verifyEthWalletTotalAssociatedBalance('1,001.00');
cy.get(vegaWallet) cy.get(vegaWallet).within(() => {
.last() cy.get(vegaWalletAssociatedBalance, txTimeout).should(
.within(() => { 'contain',
cy.get(vegaWalletAssociatedBalance, txTimeout).should( '1,001.00'
'contain', );
'1,001.00' });
);
});
}); });
it('Able to disassociate a partial amount of tokens currently associated', function () { it('Able to disassociate a partial amount of tokens currently associated', function () {
stakingPageAssociateTokens('2'); stakingPageAssociateTokens('2');
cy.get(vegaWallet) cy.get(vegaWallet).within(() => {
.first() cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
.within(() => { });
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get('button').contains('Select a validator to nominate').click(); cy.get('button').contains('Select a validator to nominate').click();
stakingPageDisassociateTokens('1'); stakingPageDisassociateTokens('1');
verifyEthWalletAssociatedBalance('1.0'); verifyEthWalletAssociatedBalance('1.0');
cy.get(vegaWallet) cy.get(vegaWallet).within(() => {
.first() cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 1.0);
.within(() => { });
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
1.0
);
});
}); });
it('Able to disassociate all tokens - using max', function () { it('Able to disassociate all tokens - using max', function () {
@@ -175,40 +155,26 @@ context(
const warningText = const warningText =
'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.'; 'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.';
stakingPageAssociateTokens('2'); stakingPageAssociateTokens('2');
cy.get(vegaWallet) cy.get(vegaWallet).within(() => {
.first() cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
.within(() => { });
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get('button').contains('Select a validator to nominate').click(); cy.get('button').contains('Select a validator to nominate').click();
cy.get(ethWalletDissociateButton).click(); cy.get(ethWalletDissociateButton).click();
cy.get(disassociationWarning).should('contain', warningText); cy.get(disassociationWarning).should('contain', warningText);
stakingPageDisassociateAllTokens(); stakingPageDisassociateAllTokens();
cy.get(ethWalletContainer) cy.get(ethWalletContainer).within(() => {
.first() cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
.within(() => { 'not.exist'
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should( );
'not.exist' });
); cy.get(ethWalletContainer).within(() => {
}); cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
cy.get(ethWalletContainer) 'not.exist'
.first() );
.within(() => { });
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should( cy.get(vegaWallet).within(() => {
'not.exist' cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 0.0);
); });
});
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
0.0
);
});
}); });
it('Able to associate and disassociate vesting contract tokens', function () { it('Able to associate and disassociate vesting contract tokens', function () {
@@ -234,14 +200,9 @@ context(
cy.getByTestId('currency-title', txTimeout).should('have.length', 6); cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
verifyEthWalletAssociatedBalance('2.0'); verifyEthWalletAssociatedBalance('2.0');
verifyEthWalletTotalAssociatedBalance('2.0'); verifyEthWalletTotalAssociatedBalance('2.0');
cy.get(vegaWallet) cy.get(vegaWallet).within(() => {
.first() cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
.within(() => { });
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0); cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
stakingPageDisassociateTokens('1', { stakingPageDisassociateTokens('1', {
type: 'contract', type: 'contract',
@@ -267,61 +228,38 @@ context(
stakingPageAssociateTokens('21', { type: 'wallet' }); stakingPageAssociateTokens('21', { type: 'wallet' });
cy.get('button').contains('Select a validator to nominate').click(); cy.get('button').contains('Select a validator to nominate').click();
stakingPageAssociateTokens('37', { type: 'contract' }); stakingPageAssociateTokens('37', { type: 'contract' });
cy.get(vestingContractSection) cy.get(vestingContractSection).within(() => {
.first() cy.get(associatedKey).should(
.within(() => { 'contain',
cy.get(associatedKey).should( Cypress.env('vegaWalletPublicKeyShort')
'contain', );
Cypress.env('vegaWalletPublicKeyShort') cy.get(associatedAmount, txTimeout).should('contain', 37);
); });
cy.get(associatedAmount, txTimeout).should('contain', 37); cy.get(vegaInWalletSection).within(() => {
}); cy.get(associatedKey).should(
cy.get(vegaInWalletSection) 'contain',
.first() Cypress.env('vegaWalletPublicKeyShort')
.within(() => { );
cy.get(associatedKey).should( cy.get(associatedAmount, txTimeout).should('contain', 21);
'contain', });
Cypress.env('vegaWalletPublicKeyShort') cy.get(vegaWallet).within(() => {
); cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 58);
cy.get(associatedAmount, txTimeout).should('contain', 21); });
});
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
58
);
});
stakingPageDisassociateTokens('6', { type: 'contract' }); stakingPageDisassociateTokens('6', { type: 'contract' });
cy.get(vestingContractSection) cy.get(vestingContractSection).within(() => {
.first() cy.get(associatedAmount, txTimeout).should('contain', 31);
.within(() => { });
cy.get(associatedAmount, txTimeout).should('contain', 31); cy.get(vegaWallet).within(() => {
}); cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 52);
cy.get(vegaWallet) });
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
52
);
});
navigateTo(navigation.validators); navigateTo(navigation.validators);
stakingPageDisassociateTokens('9', { type: 'wallet' }); stakingPageDisassociateTokens('9', { type: 'wallet' });
cy.get(vegaInWalletSection) cy.get(vegaInWalletSection).within(() => {
.first() cy.get(associatedAmount, txTimeout).should('contain', 12);
.within(() => { });
cy.get(associatedAmount, txTimeout).should('contain', 12); cy.get(vegaWallet).within(() => {
}); cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 43);
cy.get(vegaWallet) });
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
43
);
});
}); });
it('Not able to associate more tokens than owned', function () { it('Not able to associate more tokens than owned', function () {
@@ -380,14 +318,9 @@ context(
Cypress.env('vegaWalletPublicKey2') Cypress.env('vegaWalletPublicKey2')
); );
stakingPageAssociateTokens('2'); stakingPageAssociateTokens('2');
cy.get(vegaWallet) cy.get(vegaWallet).within(() => {
.first() cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
.within(() => { });
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get(associateCompleteText).should( cy.get(associateCompleteText).should(
'have.text', 'have.text',
`Vega key ${Cypress.env( `Vega key ${Cypress.env(
@@ -1,11 +1,13 @@
import { import {
navigateTo, navigateTo,
navigation, navigation,
turnTelemetryOff,
waitForSpinner, waitForSpinner,
} from '../../support/common.functions'; } from '../../support/common.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { depositAsset } from '../../support/wallet-teardown.functions'; import {
depositAsset,
vegaWalletTeardown,
} from '../../support/wallet-teardown.functions';
const withdraw = 'withdraw'; const withdraw = 'withdraw';
const withdrawalForm = 'withdraw-form'; const withdrawalForm = 'withdraw-form';
@@ -23,15 +25,6 @@ const withdrawalAmount = 'withdrawal-amount';
const withdrawalRecipient = 'withdrawal-recipient'; const withdrawalRecipient = 'withdrawal-recipient';
const withdrawFundsButton = 'withdraw-funds'; const withdrawFundsButton = 'withdraw-funds';
const completeWithdrawalButton = 'complete-withdrawal'; const completeWithdrawalButton = 'complete-withdrawal';
const tableTxHash = '[col-id="txHash"]';
const tableAssetSymbol = '[col-id="asset.symbol"]';
const tableAmount = '[col-id="amount"]';
const tableReceiverAddress = '[col-id="details.receiverAddress"]';
const tableWithdrawnTimeStamp = '[col-id="withdrawnTimestamp"]';
const tableWithdrawnStatus = '[col-id="status"]';
const tableCreatedTimeStamp = '[col-id="createdTimestamp"]';
const toastContent = 'toast-content';
const toastPanel = 'toast-panel';
const usdtName = 'USDC (local)'; const usdtName = 'USDC (local)';
const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0'; const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0';
const usdcSymbol = 'tUSDC'; const usdcSymbol = 'tUSDC';
@@ -49,24 +42,26 @@ context(
cy.visit('/'); cy.visit('/');
// When running tests locally, will fail if run without restarting capsule // When running tests locally, will fail if run without restarting capsule
cy.updateCapsuleMultiSig().then(() => { cy.updateCapsuleMultiSig().then(() => {
ethereumWalletConnect(); depositAsset(usdcEthAddress, '100');
depositAsset(usdcEthAddress, '1000', 5);
}); });
}); });
beforeEach('Navigate to withdrawal page', function () { beforeEach('Navigate to withdrawal page', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
navigateTo(navigation.withdraw); navigateTo(navigation.withdraw);
cy.connectVegaWallet(); cy.connectVegaWallet();
ethereumWalletConnect(); ethereumWalletConnect();
vegaWalletTeardown();
}); });
it('Able to open withdrawal form with vega wallet connected', function () { it('Able to open withdrawal form with vega wallet connected', function () {
// needs to reload page for withdrawal form to be displayed in ci - not reproducible outside of ci
cy.reload();
waitForSpinner();
ethereumWalletConnect();
cy.getByTestId(withdraw).should('be.visible').click(); cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(withdrawalForm, txTimeout).within(() => { cy.getByTestId(withdrawalForm).within(() => {
cy.get('select').find('option').should('have.length.at.least', 2); cy.get('select').find('option').should('have.length.at.least', 2);
cy.getByTestId(ethAddressInput).should('be.visible'); cy.getByTestId(ethAddressInput).should('be.visible');
cy.getByTestId(amountInput).should('be.visible'); cy.getByTestId(amountInput).should('be.visible');
@@ -75,7 +70,7 @@ context(
it('Unable to submit withdrawal with invalid fields', function () { it('Unable to submit withdrawal with invalid fields', function () {
cy.getByTestId(withdraw).should('be.visible').click(); cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(withdrawalForm, txTimeout).within(() => { cy.getByTestId(withdrawalForm).within(() => {
cy.get('select').select(usdtSelectValue, { force: true }); cy.get('select').select(usdtSelectValue, { force: true });
cy.getByTestId(balanceAvailable, txTimeout).should('exist'); cy.getByTestId(balanceAvailable, txTimeout).should('exist');
cy.getByTestId(submitWithdrawalButton).click(); cy.getByTestId(submitWithdrawalButton).click();
@@ -99,7 +94,7 @@ context(
it('Able to withdraw asset: -eth wallet connected -withdraw funds button', function () { it('Able to withdraw asset: -eth wallet connected -withdraw funds button', function () {
// fill in withdrawal form // fill in withdrawal form
cy.getByTestId(withdraw).should('be.visible').click(); cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(withdrawalForm, txTimeout).within(() => { cy.getByTestId(withdrawalForm).within(() => {
cy.get('select').select(usdtSelectValue, { force: true }); cy.get('select').select(usdtSelectValue, { force: true });
cy.getByTestId(balanceAvailable, txTimeout).should('exist'); cy.getByTestId(balanceAvailable, txTimeout).should('exist');
cy.getByTestId(withdrawalThreshold).should( cy.getByTestId(withdrawalThreshold).should(
@@ -107,7 +102,7 @@ context(
'100,000.00000T' '100,000.00000T'
); );
cy.getByTestId(delayTime).should('have.text', 'None'); cy.getByTestId(delayTime).should('have.text', 'None');
cy.getByTestId(amountInput).click().type('120'); cy.getByTestId(amountInput).click().type('100');
cy.getByTestId(submitWithdrawalButton).click(); cy.getByTestId(submitWithdrawalButton).click();
}); });
@@ -121,7 +116,7 @@ context(
.should('have.attr', 'href') .should('have.attr', 'href')
.and('contain', '/txs/'); .and('contain', '/txs/');
cy.getByTestId(withdrawalAssetSymbol).should('have.text', usdcSymbol); cy.getByTestId(withdrawalAssetSymbol).should('have.text', usdcSymbol);
cy.getByTestId(withdrawalAmount).should('have.text', '120.00'); cy.getByTestId(withdrawalAmount).should('have.text', '100.00');
cy.getByTestId(withdrawalRecipient) cy.getByTestId(withdrawalRecipient)
.should('have.text', truncatedWithdrawalEthAddress) .should('have.text', truncatedWithdrawalEthAddress)
.and('have.attr', 'href') .and('have.attr', 'href')
@@ -133,36 +128,43 @@ context(
'Withdraw asset complete' 'Withdraw asset complete'
); );
cy.getByTestId(dialogClose).click(); cy.getByTestId(dialogClose).click();
// need to reload page to see withdrawal history complete
cy.reload();
waitForAssetsDisplayed(usdtName);
// withdrawal history for complete withdrawal displayed // withdrawal history for complete withdrawal displayed
cy.get(tableWithdrawnStatus) cy.get('[col-id="txHash"]', txTimeout)
.eq(1, txTimeout) .should('have.length.above', 1)
.should('have.text', 'Completed') .eq(1)
.parent() .parent()
.within(() => { .within(() => {
cy.get(tableAssetSymbol).should('have.text', usdcSymbol); cy.get('[col-id="asset.symbol"]').should('have.text', usdcSymbol);
cy.get(tableAmount).should('have.text', '120.00'); cy.get('[col-id="amount"]').should('have.text', '100.00');
cy.get(tableReceiverAddress) cy.get('[col-id="details.receiverAddress"]')
.find('a') .find('a')
.should('have.attr', 'href') .should('have.attr', 'href')
.and('contain', 'https://sepolia.etherscan.io/address/'); .and('contain', 'https://sepolia.etherscan.io/address/');
cy.get(tableWithdrawnTimeStamp).should('not.be.empty'); cy.get('[col-id="withdrawnTimestamp"]').should('not.be.empty');
cy.get(tableTxHash) cy.get('[col-id="status"]').should('have.text', 'Completed');
cy.get('[col-id="txHash"]')
.find('a') .find('a')
.should('have.attr', 'href') .should('have.attr', 'href')
.and('contain', 'https://sepolia.etherscan.io/tx/'); .and('contain', 'https://sepolia.etherscan.io/tx/');
}); });
}); });
it('Able to withdraw asset: -eth wallet not connected', function () { // Skipping because of bug #1857
it.skip('Able to withdraw asset: -eth wallet not connected', function () {
const ethWalletAddress = Cypress.env('ethWalletPublicKey'); const ethWalletAddress = Cypress.env('ethWalletPublicKey');
cy.reload(); cy.reload();
waitForAssetsDisplayed(usdtName); waitForAssetsDisplayed(usdtName);
// fill in withdrawal form // fill in withdrawal form
cy.getByTestId(withdraw).should('be.visible').click(); cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(withdrawalForm, txTimeout).within(() => { cy.getByTestId(withdrawalForm).within(() => {
cy.get('select').select(usdtSelectValue, { force: true }); cy.get('select').select(usdtSelectValue, { force: true });
cy.getByTestId(ethAddressInput).should('be.empty'); cy.getByTestId(ethAddressInput).should('be.empty');
cy.getByTestId(amountInput).click().type('110'); cy.getByTestId(amountInput).click().type('100');
cy.getByTestId(submitWithdrawalButton).click(); cy.getByTestId(submitWithdrawalButton).click();
// Need eth address to submit withdrawal // Need eth address to submit withdrawal
@@ -178,38 +180,20 @@ context(
'Transaction complete' 'Transaction complete'
); );
cy.getByTestId(dialogClose).click(); cy.getByTestId(dialogClose).click();
cy.get(tableTxHash)
.eq(1) cy.getByTestId(completeWithdrawalButton)
.should('have.text', 'Complete withdrawal') .eq(0)
.parent()
.parent() .parent()
.within(() => { .within(() => {
cy.get(tableAssetSymbol).should('have.text', usdcSymbol); cy.get('[col-id="asset.symbol"]').should('have.text', usdcSymbol);
cy.get(tableAmount).should('have.text', '110.00'); cy.get('[col-id="amount"]').should('have.text', '100.00');
cy.get(tableReceiverAddress) cy.get('[col-id="details.receiverAddress"]')
.find('a') .find('a')
.should('have.attr', 'href') .should('have.attr', 'href')
.and('contain', 'https://sepolia.etherscan.io/address/'); .and('contain', 'https://sepolia.etherscan.io/address/');
cy.get(tableCreatedTimeStamp).should('not.be.empty'); cy.get('[col-id="createdTimestamp"]').should('not.be.empty');
}); cy.getByTestId(completeWithdrawalButton).click();
ethereumWalletConnect();
cy.getByTestId(completeWithdrawalButton).click();
cy.getByTestId(toastContent)
.last()
.should('contain.text', 'Awaiting confirmation')
.within(() => {
cy.getByTestId('external-link').should('exist');
});
cy.getByTestId(toastContent)
.first()
.should('contain.text', 'The withdrawal has been approved.')
.within(() => {
cy.getByTestId(toastPanel).should('contain.text', '110.00', 'tUSDC');
});
cy.getByTestId(toastContent)
.last()
.should('contain.text', 'Transaction confirmed')
.within(() => {
cy.getByTestId('external-link').should('exist');
}); });
}); });
@@ -218,31 +202,26 @@ context(
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`; const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
// Disconnect vega wallet // Disconnect vega wallet
cy.getByTestId('manage-vega-wallet').last().click(); cy.getByTestId('manage-vega-wallet').click();
cy.getByTestId('disconnect').click(); cy.getByTestId('disconnect').click();
cy.connectPublicKey(vegaWalletPubKey); cy.connectPublicKey(vegaWalletPubKey);
cy.getByTestId(withdraw).should('be.visible').click(); cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(withdrawalForm, txTimeout).within(() => { cy.getByTestId(withdrawalForm).within(() => {
cy.get('select').select(usdtSelectValue, { force: true }); cy.get('select').select(usdtSelectValue, { force: true });
cy.getByTestId(balanceAvailable, txTimeout).should('exist'); cy.getByTestId(balanceAvailable, txTimeout).should('exist');
cy.getByTestId(amountInput).click().type('100'); cy.getByTestId(amountInput).click().type('100');
cy.getByTestId(submitWithdrawalButton).click(); cy.getByTestId(submitWithdrawalButton).click();
}); });
cy.getByTestId('dialog-content') cy.getByTestId('dialog-content').within(() => {
.last() cy.get('h1').should('have.text', 'Transaction failed');
.within(() => { cy.getByTestId('Error').should('have.text', expectedErrorTxt);
cy.get('h1').should('have.text', 'Transaction failed'); });
cy.getByTestId('Error').should('have.text', expectedErrorTxt);
});
}); });
function waitForAssetsDisplayed(expectedAsset: string) { function waitForAssetsDisplayed(expectedAsset: string) {
cy.getByTestId('currency-title', txTimeout).should( cy.contains(expectedAsset, txTimeout).should('be.visible');
'contain.text',
expectedAsset
);
} }
} }
); );
@@ -27,7 +27,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
cy.getByTestId('app-announcement').should('not.exist'); cy.getByTestId('app-announcement').should('not.exist');
}); });
it('should show open or enacted proposals without proposal summary', function () { it('should show open or enacted proposals with proposal summary', function () {
cy.get('body').then(($body) => { cy.get('body').then(($body) => {
if (!$body.find('[data-testid="proposals-list-item"]').length) { if (!$body.find('[data-testid="proposals-list-item"]').length) {
cy.createMarket(); cy.createMarket();
@@ -43,6 +43,12 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
.invoke('text') .invoke('text')
.should('not.be.empty'); .should('not.be.empty');
cy.getByTestId('proposal-type').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') cy.getByTestId('proposal-status')
.invoke('text') .invoke('text')
.should('not.be.empty'); .should('not.be.empty');
@@ -125,7 +131,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
.within(() => { .within(() => {
cy.get('span') cy.get('span')
.first() .first()
.should('have.text', 'http://localhost:3008/graphql'); .should('have.text', 'http://localhost:3028/query');
cy.getByTestId('link').should('exist'); cy.getByTestId('link').should('exist');
}); });
}); });
@@ -161,7 +167,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
cy.getByTestId('menu-drawer').should('be.visible'); cy.getByTestId('menu-drawer').should('be.visible');
}); });
it.skip('should have link for proposal page', function () { it('should have link for proposal page', function () {
cy.getByTestId('menu-drawer').within(() => { cy.getByTestId('menu-drawer').within(() => {
cy.get('[href="/proposals"]') cy.get('[href="/proposals"]')
.should('exist') .should('exist')
@@ -54,7 +54,7 @@ context(
}); });
}); });
it.skip('should be able to see button for - new proposal', function () { it('should be able to see button for - new proposal', function () {
// 3001-VOTE-002 // 3001-VOTE-002
cy.get(newProposalLink) cy.get(newProposalLink)
.should('be.visible') .should('be.visible')
@@ -63,7 +63,7 @@ context(
.and('equal', '/proposals/propose'); .and('equal', '/proposals/propose');
}); });
it.skip('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () { it('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () {
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER); goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.get(connectToVegaWalletButton) cy.get(connectToVegaWalletButton)
.should('be.visible') .should('be.visible')
@@ -101,15 +101,15 @@ context(
); );
cy.getByTestId('protocol-upgrade-proposal-release-tag').should( cy.getByTestId('protocol-upgrade-proposal-release-tag').should(
'have.text', 'have.text',
'Vega release tag: v1' 'Vega release tagv1'
); );
cy.getByTestId('protocol-upgrade-proposal-block-height').should( cy.getByTestId('protocol-upgrade-proposal-block-height').should(
'have.text', 'have.text',
'Upgrade block height: 2015942' 'Upgrade block height2015942'
); );
cy.getByTestId('protocol-upgrade-proposal-status').should( cy.getByTestId('protocol-upgrade-proposal-status').should(
'have.text', 'have.text',
'Approved by validators ' 'Approved'
); );
}); });
}); });
@@ -136,7 +136,7 @@ context(
); );
cy.getByTestId('protocol-upgrade-state').should( cy.getByTestId('protocol-upgrade-state').should(
'have.text', 'have.text',
'Approved by validators' 'Approved'
); );
cy.getByTestId('protocol-upgrade-release-tag').should( cy.getByTestId('protocol-upgrade-release-tag').should(
'have.text', 'have.text',
@@ -3,7 +3,6 @@
import { import {
navigateTo, navigateTo,
navigation, navigation,
turnTelemetryOff,
waitForSpinner, waitForSpinner,
} from '../../support/common.functions'; } from '../../support/common.functions';
import { import {
@@ -18,16 +17,10 @@ const banner = 'view-banner';
context('View functionality with public key', { tags: '@smoke' }, function () { context('View functionality with public key', { tags: '@smoke' }, function () {
before('send asset to wallet', function () { before('send asset to wallet', function () {
vegaWalletFaucetAssetsWithoutCheck( vegaWalletFaucetAssetsWithoutCheck('fUSDC', '1000000', vegaWalletPubKey);
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc',
'1000000',
vegaWalletPubKey
);
}); });
beforeEach('visit home page', function () { beforeEach('visit home page', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.visit('/'); cy.visit('/');
waitForSpinner(); waitForSpinner();
cy.connectPublicKey(vegaWalletPubKey); cy.connectPublicKey(vegaWalletPubKey);
@@ -46,7 +39,7 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
.and('contain.text', 'USDC (fake)'); .and('contain.text', 'USDC (fake)');
}); });
it.skip('Unable to submit proposal with public key', function () { it('Unable to submit proposal with public key', function () {
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`; const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
@@ -29,10 +29,11 @@ const performancePenaltyToolTip = '[data-testid="performance-penalty-tooltip"]';
const overstakedPenaltyToolTip = '[data-testid="overstaked-penalty-tooltip"]'; const overstakedPenaltyToolTip = '[data-testid="overstaked-penalty-tooltip"]';
const totalPenaltyToolTip = '[data-testid="total-penalty-tooltip"]'; const totalPenaltyToolTip = '[data-testid="total-penalty-tooltip"]';
const epochCountDown = '[data-testid="epoch-countdown"]'; const epochCountDown = '[data-testid="epoch-countdown"]';
const stakeNumberRegex = /^\d{1,3}(,\d{3})*(\.\d+)?$/; const stakeNumberRegex = /^\d*\.?\d*$/;
context('Validators Page - verify elements on page', function () { context('Validators Page - verify elements on page', function () {
before('navigate to validators page', function () { before('navigate to validators page', function () {
cy.clearAllLocalStorage();
cy.visit('/validators'); cy.visit('/validators');
}); });
@@ -84,13 +85,13 @@ context('Validators Page - verify elements on page', function () {
cy.get(stakedByOperatorToolTip) cy.get(stakedByOperatorToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Staked by operator: 3,000.00'); .should('contain', 'Staked by operator: 0.00');
cy.get(stakedByDelegatesToolTip) cy.get(stakedByDelegatesToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Staked by delegates: 0.00'); .should('contain', 'Staked by delegates: 0.00');
cy.get(totalStakedToolTip) cy.get(totalStakedToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Total stake: 3,000.00'); .should('contain', 'Total stake: 0.00');
}); });
it('Should be able to see validator normalised voting power', function () { it('Should be able to see validator normalised voting power', function () {
@@ -106,10 +107,10 @@ context('Validators Page - verify elements on page', function () {
cy.get(unnormalisedVotingPowerToolTip) cy.get(unnormalisedVotingPowerToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Unnormalised voting power: 20.00%'); .should('contain', 'Unnormalised voting power: 0.00%');
cy.get(normalisedVotingPowerToolTip) cy.get(normalisedVotingPowerToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Normalised voting power: 50.00%'); .should('contain', 'Normalised voting power: 0.10%');
}); });
// 2002-SINC-018 // 2002-SINC-018
@@ -126,13 +127,13 @@ context('Validators Page - verify elements on page', function () {
cy.get(performancePenaltyToolTip) cy.get(performancePenaltyToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Performance penalty: 0.00%'); .should('contain', 'Performance penalty: 100.00%');
cy.get(overstakedPenaltyToolTip) cy.get(overstakedPenaltyToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Overstaked penalty: 60.00%'); // value not asserted due to #2886 .should('contain', 'Overstaked penalty:'); // value not asserted due to #2886
cy.get(totalPenaltyToolTip) cy.get(totalPenaltyToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Total penalties: 60.00%'); .should('contain', 'Total penalties: 0.00%');
}); });
it('Should be able to see validator pending stake', function () { it('Should be able to see validator pending stake', function () {
@@ -35,6 +35,7 @@ context(
{ tags: '@regression' }, { tags: '@regression' },
() => { () => {
before('visit token home page', () => { before('visit token home page', () => {
cy.clearAllLocalStorage();
cy.visit('/'); cy.visit('/');
cy.get(walletContainer, { timeout: 60000 }).should('be.visible'); cy.get(walletContainer, { timeout: 60000 }).should('be.visible');
}); });
@@ -281,30 +282,26 @@ context(
describe('Vega wallet with assets', function () { describe('Vega wallet with assets', function () {
const assets = [ const assets = [
{ {
id: '816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc', id: 'fUSDC',
name: 'USDC (fake)', name: 'USDC (fake)',
symbol: 'fUSDC',
amount: '1000000', amount: '1000000',
expectedAmount: '10.00', expectedAmount: '10.00',
}, },
{ {
id: '8566db7257222b5b7ef2886394ad28b938b28680a54a169bbc795027b89d6665', id: 'fDAI',
name: 'DAI (fake)', name: 'DAI (fake)',
symbol: 'fDAI',
amount: '200000', amount: '200000',
expectedAmount: '2.00', expectedAmount: '2.00',
}, },
{ {
id: '73174a6fb1d5802ba0ac7bd7ab79e0a3a4837b262de0a4e80815a55442692bd0', id: 'fBTC',
name: 'BTC (fake)', name: 'BTC (fake)',
symbol: 'fBTC',
amount: '600000', amount: '600000',
expectedAmount: '6.00', expectedAmount: '6.00',
}, },
{ {
id: 'e02d4c15d790d1d2dffaf2dcd1cf06a1fe656656cf4ed18c8ce99f9e83643567', id: 'fEURO',
name: 'EURO (fake)', name: 'EURO (fake)',
symbol: 'fEURO',
amount: '800000', amount: '800000',
expectedAmount: '8.00', expectedAmount: '8.00',
}, },
@@ -325,15 +322,15 @@ context(
}); });
}); });
for (const { name, symbol, expectedAmount } of assets) { for (const { id, name, expectedAmount } of assets) {
it(`should see ${name} within vega wallet`, () => { it(`should see ${id} within vega wallet`, () => {
cy.get(walletContainer).within(() => { cy.get(walletContainer).within(() => {
cy.get(vegaWalletCurrencyTitle) cy.get(vegaWalletCurrencyTitle)
.contains(name, txTimeout) .contains(id, txTimeout)
.should('be.visible'); .should('be.visible');
cy.get(vegaWalletCurrencyTitle) cy.get(vegaWalletCurrencyTitle)
.contains(name) .contains(id)
.parent() .parent()
.siblings() .siblings()
.invoke('text') .invoke('text')
@@ -341,9 +338,9 @@ context(
.should('be.gte', parseFloat(expectedAmount)); .should('be.gte', parseFloat(expectedAmount));
cy.get(vegaWalletCurrencyTitle) cy.get(vegaWalletCurrencyTitle)
.contains(name) .contains(id)
.parent() .parent()
.contains(symbol); .contains(name);
}); });
}); });
} }
@@ -12,6 +12,7 @@ context(
{ tags: '@smoke' }, { tags: '@smoke' },
function () { function () {
before('navigate to withdrawals page', function () { before('navigate to withdrawals page', function () {
cy.clearAllLocalStorage();
cy.visit('/'); cy.visit('/');
navigateTo(navigation.withdraw); navigateTo(navigation.withdraw);
}); });
@@ -90,10 +90,3 @@ export function verifyEthWalletAssociatedBalance(amount: string) {
export function closeDialog() { export function closeDialog() {
cy.getByTestId('dialog-close').click(); cy.getByTestId('dialog-close').click();
} }
export function turnTelemetryOff() {
// Ensuring the telemetry modal doesn't disrupt the tests
cy.window().then((win) =>
win.localStorage.setItem('vega_telemetry_on', 'false')
);
}
@@ -1,4 +1,3 @@
import { format } from 'date-fns';
import { closeDialog, navigateTo, navigation } from './common.functions'; import { closeDialog, navigateTo, navigation } from './common.functions';
import { ensureSpecifiedUnstakedTokensAreAssociated } from './staking.functions'; import { ensureSpecifiedUnstakedTokensAreAssociated } from './staking.functions';
@@ -16,6 +15,35 @@ const newProposalSubmitButton = '[data-testid="proposal-submit"]';
const epochTimeout = Cypress.env('epochTimeout'); const epochTimeout = Cypress.env('epochTimeout');
const proposalTimeout = { timeout: 14000 }; const proposalTimeout = { timeout: 14000 };
export function convertUnixTimestampToDateformat(
unixTimestamp: number,
monthTextLength = 'longMonth'
) {
const dateSupplied = new Date(unixTimestamp * 1000);
const year = dateSupplied.getFullYear();
const months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
const month = months[dateSupplied.getMonth()];
const shortMonth = months[dateSupplied.getMonth()].substring(0, 3),
date = dateSupplied.getDate();
if (monthTextLength === 'longMonth') {
return cy.wrap(`${date} ${month} ${year}`);
} else return cy.wrap(`${date} ${shortMonth} ${year}`);
}
export function createTenDigitUnixTimeStampForSpecifiedDays( export function createTenDigitUnixTimeStampForSpecifiedDays(
durationDays: number durationDays: number
) { ) {
@@ -24,13 +52,6 @@ export function createTenDigitUnixTimeStampForSpecifiedDays(
return (timestamp = Math.floor(timestamp / 1000)); return (timestamp = Math.floor(timestamp / 1000));
} }
export function getDateFormatForSpecifiedDays(days: number) {
const date = new Date(
createTenDigitUnixTimeStampForSpecifiedDays(days) * 1000
);
return cy.wrap(format(date, 'dd MMM yyyy'));
}
export function enterRawProposalBody(timestamp: number) { export function enterRawProposalBody(timestamp: number) {
cy.fixture('/proposals/raw.json').then((rawProposal) => { cy.fixture('/proposals/raw.json').then((rawProposal) => {
rawProposal.terms.closingTimestamp = timestamp; rawProposal.terms.closingTimestamp = timestamp;
@@ -69,7 +90,6 @@ export function getSubmittedProposalFromProposalList(proposalTitle: string) {
export function getProposalIdFromList(proposalTitle: string) { export function getProposalIdFromList(proposalTitle: string) {
cy.contains(proposalTitle) cy.contains(proposalTitle)
.parentsUntil(proposalListItem) .parentsUntil(proposalListItem)
.last()
.within(() => { .within(() => {
cy.get(proposalDetails) cy.get(proposalDetails)
.invoke('text') .invoke('text')
@@ -83,6 +103,16 @@ export function getProposalIdFromList(proposalTitle: string) {
}); });
} }
export function getGovernanceProposalDateFormatForSpecifiedDays(
days: number,
shortOrLong?: string
) {
return convertUnixTimestampToDateformat(
createTenDigitUnixTimeStampForSpecifiedDays(days),
shortOrLong
);
}
export function getProposalInformationFromTable(heading: string) { export function getProposalInformationFromTable(heading: string) {
return cy.get(proposalInformationTableRows).contains(heading).siblings(); return cy.get(proposalInformationTableRows).contains(heading).siblings();
} }
@@ -103,7 +133,7 @@ export function waitForProposalSync() {
// before proposal appears in the list - so rather than hard coded wait - we just wait on the // before proposal appears in the list - so rather than hard coded wait - we just wait on the
// delegation checks that are performed on the governance page. // delegation checks that are performed on the governance page.
cy.intercept('POST', '/graphql', (req) => { cy.intercept('POST', '/query', (req) => {
if (req.body.operationName === 'Delegations') { if (req.body.operationName === 'Delegations') {
req.alias = 'proposalDelegationsCompletion'; req.alias = 'proposalDelegationsCompletion';
} }
@@ -113,7 +143,7 @@ export function waitForProposalSync() {
cy.wait(['@proposalDelegationsCompletion', '@proposalDelegationsCompletion']); cy.wait(['@proposalDelegationsCompletion', '@proposalDelegationsCompletion']);
// Turn off this intercept from here on in // Turn off this intercept from here on in
cy.intercept('POST', '/graphql', (req) => { cy.intercept('POST', '/query', (req) => {
if (req.body.operationName === 'Delegations') { if (req.body.operationName === 'Delegations') {
req.continue(); req.continue();
} }

Some files were not shown because too many files have changed in this diff Show More