Compare commits

..
Author SHA1 Message Date
sam-keen 1a22d11447 Merge remote-tracking branch 'origin/develop' into fix/claim 2023-05-12 14:29:43 +01:00
Mikołaj Młodzikowski d5f0bd419e feat(ci): update vega landing page whenever new console is released (#3751) 2023-05-12 15:18:15 +02:00
Sam KeenandBartłomiej Głownia 2c7934a8c7 fix(governance): fix time delay notice for withdrawal of 0.00 assets (#3740)
Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
2023-05-12 15:04:53 +02:00
Joe Tsang fae61c28ca chore(cypress): remove cypress project id (#3739) 2023-05-12 13:44:22 +01:00
dexturr fcd4541625 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-12 12:10:20 +00:00
Sam KeenandJoe 8e0a92fdec fix(governance): network upgrade proposal e2e test tweak (#3748)
Co-authored-by: Joe <joe@vega.xyz>
2023-05-12 09:58:10 +01:00
Dexter 2cb4aa1029 fix: claim not encoding ascii correctly 2023-05-12 08:59:15 +01:00
dexturr 6e7109ed87 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-12 06:09:45 +00:00
dexturr f2c698ce06 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-12 00:16:15 +00:00
dexturr ad9a3a3400 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-11 18:10:08 +00:00
Sam Keen efeac49d58 feat(governance): change status labels for network upgrade proposals (#3711) 2023-05-11 15:43:27 +00:00
Mikołaj Młodzikowski 2d430710ab feat(ci): use actual secret in the script 2023-05-11 17:31:12 +02:00
Mikołaj Młodzikowski bca1a98985 fix(ci): remove old dockerfile 2023-05-11 17:16:28 +02:00
Edd 8a080d3279 fix(explorer): fix bug where no votes displayed a yes icon (#3699) 2023-05-11 14:55:00 +00:00
Mikołaj Młodzikowski f121836b4e feat(ci): fleek updates (#3724) 2023-05-11 15:42:35 +02:00
Sam Keen b641c82ad8 feat(governance): voting blog link and button title (#3717) 2023-05-11 12:59:28 +00:00
Sam Keen bf73559c30 fix(governance): change proposal sort order (#3716) 2023-05-11 12:39:30 +00:00
dexturr 653cec2592 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-11 12:07:57 +00:00
m.ray 579c884a5a feat(trading): show pegged order offset and reference in the order table (#3675) 2023-05-11 12:43:20 +01:00
Bartłomiej Głownia b2279c7e47 feat(trading): hook up new EstimatePosition and EstimateFees api methods (#3634) 2023-05-11 12:58:12 +02:00
Sam Keen a8c17b6807 fix(governance): tranches data (#3708) 2023-05-11 10:22:52 +00:00
Sam Keen b4c7dc6f59 fix(governance): more thorough catch for url in error reporting (#3686) 2023-05-11 10:21:16 +00:00
daro-maj d44392bebf test(trading): show full oracle profile info in markets test (#3695) 2023-05-11 08:18:00 +02:00
dexturr bd679957e2 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-11 06:07:33 +00:00
dexturr e30d48555e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-11 00:16:19 +00:00
Sam Keen b4b2416780 fix(governance): my stake share 2 dp (#3685) 2023-05-10 16:23:37 +00:00
Maciek dc7832ac81 chore(candles-chart): fill up missing candles (#3664) 2023-05-10 15:26:27 +00:00
Joe Tsang 91207d31ee chore(governance): fix failing validator tests (#3703) 2023-05-10 15:03:47 +00:00
dexturr 58efb460a6 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-10 12:10:00 +00:00
Mikołaj Młodzikowski 044f98777b feat(ci): lint makefile 2023-05-10 13:43:33 +02:00
Mikołaj Młodzikowski 00fdc5e81a fix(ci): preparing dist bash syntax 2023-05-10 13:33:17 +02:00
Mikołaj Młodzikowski adfad3bafb feat(ci): fix typo 2023-05-10 13:21:53 +02:00
dexturr e6ae88905c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-10 06:07:15 +00:00
dexturr 3953ed9953 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-10 00:15:02 +00:00
Matthew Russell b48ab58e6a chore: add VEGA_URL for explorer mainnet 2023-05-09 14:06:10 -07:00
Matthew Russell e44cf1ff53 chore(environment,trading): fix unit tests for footer and node switcher (#3682) 2023-05-09 13:39:17 -07:00
Matthew Russell bded1d32ba feat(explorer,governance): always allow selecting a node, add node guard (#3678) 2023-05-09 12:58:09 -07:00
Edd 76ddf45f4c fix(explorer): add envs back to env (#3677) 2023-05-09 12:57:38 -07:00
Dexter Edwards 6a2c9004d8 fix(governance, console, explorer): show vega node in list, cache bust (#3676) 2023-05-09 12:57:11 -07:00
dexturr 77ee88b43e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-09 18:09:50 +00:00
Dexter e4958ce3c0 fix: do not show validators with 0 self stake in list 2023-05-09 18:25:20 +01:00
Mikołaj Młodzikowski ecedb879f8 fix(ci): define which app ipfs hash is set for 2023-05-09 18:47:50 +02:00
m.ray 89700803d6 fix(trading): fix release script for mainnet (#3669) 2023-05-09 16:30:05 +00:00
Mikołaj Młodzikowski 65c9fa5df2 feat(ci): establish build based on docker to produce ipfs-hashes (#3612) 2023-05-09 18:24:39 +02:00
ArtandMadalina Raicu 02399c40fc fix(trading): welcome dialog links (#3656)
Co-authored-by: Madalina Raicu <madalina@raygroup.uk>
2023-05-09 15:43:36 +00:00
Sam Keen 2cb3b55a3b fix(governance): total supply displayed (#3666) 2023-05-09 15:33:07 +00:00
Sam Keen 3acc0e2401 fix(governance): consensus table works without previous epoch (#3663) 2023-05-09 15:14:04 +00:00
Dexter c734556eb4 ci: force build 2023-05-09 16:09:50 +01:00
Sam KeenandJoe 792ff1fc1f feat(governance): hide make proposal journey and link to docs instead (#3658)
Co-authored-by: Joe <joe@vega.xyz>
2023-05-09 14:43:39 +00:00
Sam KeenandJoe 3740a97d7e feat(governance): token references to governance (#3657)
Co-authored-by: Joe <joe@vega.xyz>
2023-05-09 14:17:40 +00:00
Dexter 20350ae2cf ci: force build 2023-05-09 15:13:53 +01:00
Dexter Edwards 50e93dad64 chore(explorer,trading,governance): new data node & explorer service urls (#3653) 2023-05-09 14:33:33 +01:00
Sam KeenandJoe c87c4bbc91 feat(governance): opt in/out telemetry (#3638)
Co-authored-by: Joe <joe@vega.xyz>
2023-05-09 13:32:16 +01:00
m.ray 00679c75f2 fix(toasts): proposal toasts timeout (#3645) 2023-05-09 10:03:17 +00:00
Art 7fe722dad0 fix(explorer): use data provider import (#3648) 2023-05-09 09:46:24 +00:00
Maciek 0d8a74dfd0 fix(trading): wrong hover effect on datagrid (#3647) 2023-05-09 09:26:59 +00:00
Edd 928b899c46 fix(explorer): improve party page loading (#3274) 2023-05-09 09:43:12 +01:00
Bartłomiej Głownia 72d93bb568 feat(trading): update fills queries, fix empty fills list issue (#3636) 2023-05-09 08:40:06 +00:00
Matthew Russell db75261cd5 chore(react-helpers): remove ag-grid deps (#3628) 2023-05-09 09:04:33 +01:00
Joe Tsang 66fbe28cf0 test(governance): e2e test to include withdrawal toasts (#3624) 2023-05-09 09:03:45 +01:00
Edd 9f3b8ecade fix(explorer): set explorer url env var in explorer (#3622) 2023-05-09 09:03:35 +01:00
Matthew Russell cd13c61e90 fix(datagrid): remove default balham borders (#3642) 2023-05-09 09:02:39 +01:00
Maciek 246577f401 feat(trading): persist table column sizes (#3595) 2023-05-09 08:09:53 +02:00
dexturr 503ca26f68 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-09 06:07:05 +00:00
dexturr 13e374a6bb chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-09 00:15:01 +00:00
Art bed411040c chore(trading): make limit default order type (#3619) 2023-05-08 15:48:43 -07:00
Joe Tsang d0173f15b2 chore(governance): assert proposal dates (#3610) 2023-05-08 15:48:14 -07:00
Matthew Russell 106b040977 chore(utils): remove ethers deps from ui-toolkit (#3627) 2023-05-08 14:40:31 -07:00
dexturr bf84b04a30 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-08 18:07:04 +00:00
Matthew Russell 9f442698a4 fix(explorer): network params fixture lookup for updateAsset proposals (#3633) 2023-05-08 17:29:29 +01:00
daro-maj d1265a6af7 test(trading): update of capsule and live tests (#3635) 2023-05-08 16:52:33 +02:00
Sam Keen 313eff1c95 feat(governance): proposal details page improvements (#3611) 2023-05-08 12:41:55 +00:00
dexturr 7f949a276c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-08 12:10:52 +00:00
dexturr 76a53dc7e3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-08 06:08:30 +00:00
Matthew Russell 72821dd183 chore(utils,react-helpers,data-provider): remove apollo deps from ui-toolkit (#3626) 2023-05-07 18:01:07 -07:00
dexturr 40d2e033e0 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-08 00:15:27 +00:00
Edd e6d0b6ac1f fix(explorer): number formatting for updateasset proposals (#3630) 2023-05-07 18:17:57 +00:00
dexturr 99161497fe chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-07 18:08:18 +00:00
Edd bf6ab32230 feat(governance): render markdown in proposal view (#3632) 2023-05-07 17:45:19 +01:00
dexturr 28bcb4ada1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-07 12:10:24 +00:00
dexturr 5812c8858d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-07 06:07:03 +00:00
dexturr abf146895d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-07 00:16:07 +00:00
dexturr 4476e6c6d1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-06 18:09:41 +00:00
dexturr d967000e8f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-06 12:09:52 +00:00
dexturr 91d3d97399 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-06 06:07:05 +00:00
dexturr ca700aa103 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-06 00:14:21 +00:00
dexturr 265bf7fb35 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 18:08:29 +00:00
Sam Keen 7a5c6f3a25 fix(governance): added toasts for withdrawals (#3621) 2023-05-05 14:10:21 +00:00
dexturr 91e3460e9d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 12:10:43 +00:00
Art cf0c45aaa5 fix(trading): asset balance being rendered when disconnected from eth… (#3618) 2023-05-05 13:00:15 +02:00
m.rayandasiaznik bf63f9d46d feat(oracles): oracle full profile (#3545)
Co-authored-by: asiaznik <artur@vegaprotocol.io>
2023-05-05 09:52:03 +00:00
dexturr 023a83e0f7 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 06:08:12 +00:00
dexturr 4f6ed1eadf chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 00:14:53 +00:00
m.ray 85e293f3ec fix(liquidity): use LP order ID as ag-grid row ID (#3615) 2023-05-04 16:23:33 -07:00
dexturr 7b15d2db10 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-04 18:07:23 +00:00
m.ray b1b9695998 fix(liquidity): rows duplicated wrong ag-grid row ID (#3614) 2023-05-04 17:23:52 +00:00
Edd 6b8b33a78b chore(explorer,trading,governance): remove stagnet3 (#3608) 2023-05-04 16:50:39 +00:00
Mikołaj Młodzikowski 4fd0f6819a feat(ci): deploy develop to stagnet1 (#3609) 2023-05-04 14:29:31 +00:00
Mikołaj Młodzikowski 5032d87f98 feat(ci): define max lenght of a branch (#3607) 2023-05-04 16:06:46 +02:00
Matthew Russell b15d9cb7dc fix(governance,trading): validator testnet link for governance app (#3599) 2023-05-04 15:21:24 +02:00
dexturr 6aa7cc5bab chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-04 12:09:32 +00:00
Bartłomiej Głownia c37f9ebe66 feat(trading): divide order tab into open, closed, rejected and all (#3541) 2023-05-04 12:09:55 +02:00
Art 768b3b29f0 feat(trading): protocol upgrade notification (#3517) 2023-05-04 09:51:24 +02:00
dexturr 378946f22b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-04 06:07:49 +00:00
dexturr 523598645a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-04 00:13:39 +00:00
Art a9267de653 feat(trading): asset balances inside asset selector (deposit, withdraw form) (#3590) 2023-05-03 20:35:05 +01:00
dexturr ce22da1c9a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-03 18:09:05 +00:00
486 changed files with 7553 additions and 3934 deletions
+16
View File
@@ -0,0 +1,16 @@
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
+3 -3
View File
@@ -5,6 +5,8 @@ on:
branches:
- release/*
- develop
tags:
- v*
pull_request:
types:
- opened
@@ -97,15 +99,13 @@ jobs:
- name: See affected apps
run: |
echo ">>>> debug"
echo "NX Version: $nx_version"
echo "NX_BASE: ${{ env.NX_BASE }}"
echo "NX_HEAD: ${{ env.NX_HEAD }}"
echo ">>>> eof debug"
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)"
echo -n "Affected projects: $affected"
branch_slug="$(echo ${{ github.head_ref || github.ref_name }} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g )"
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=""
preview_governance="not deployed"
preview_trading="not deployed"
-1
View File
@@ -33,5 +33,4 @@ jobs:
config: baseUrl=${{ github.event.inputs.url }}
env: grepTags=@live
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -66,7 +66,7 @@ jobs:
######
- name: Run Cypress tests
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome --env.grepTags="${{ inputs.tags }}"
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --browser chrome --env.grepTags="${{ inputs.tags }}"
working-directory: frontend-monorepo
env:
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
+88 -35
View File
@@ -30,13 +30,21 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to the Container registry
- name: Log in to the Container registry (ghcr)
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
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
uses: actions/setup-node@v3
with:
@@ -54,30 +62,24 @@ jobs:
- name: Define variables
run: |
envName=''
dockerfile="dist.Dockerfile"
if [[ "${{ github.event_name }}" = "push" ]]; then
domain="vega.rocks"
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
if [[ "${{ github.ref }}" =~ .*mainnet.* ]]; then
domain="vega.community"
if [[ "${{ matrix.app }}" = "trading" ]]; then
dockerfile="ipfs.Dockerfile"
fi
fi
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
envName="stagnet3"
envName="stagnet1"
elif [[ "${{ matrix.app}}" = "trading" ]] && [[ ${{ startsWith(github.ref, 'refs/tags/v') && 'true' || 'false' }} = "true" ]]; then
envName="mainnet"
fi
bucketName="${{ matrix.app }}.${envName}.${domain}"
echo BUCKET_NAME=${bucketName} >> $GITHUB_ENV
fi
nodeVersion=$(cat .nvmrc | head -n 1)
echo ENV_NAME=${envName} >> $GITHUB_ENV
echo NODE_VERSION=${nodeVersion} >> $GITHUB_ENV
echo DOCKERFILE=docker/${dockerfile} >> $GITHUB_ENV
- name: Build local dist
if: ${{ env.DOCKERFILE != 'docker/ipfs.Dockerfile' }}
run: |
flags=""
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
@@ -98,62 +100,60 @@ jobs:
- name: Build and export to local Docker
id: docker_build
if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
uses: docker/build-push-action@v3
with:
context: .
file: ${{ env.DOCKERFILE }}
file: docker/node-outside-docker.Dockerfile
load: true
build-args: |
APP=${{ matrix.app }}
NODE_VERSION=${{ env.NODE_VERSION }}
ENV_NAME=${{ env.ENV_NAME }}
tags: |
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
- name: Image digest
if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
if: ${{ github.event_name == 'pull_request' }}
run: echo ${{ steps.docker_build.outputs.digest }}
- name: Sanity check docker image
if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
run: |
echo "Check ipfs-hash"
if [[ "${{ env.DOCKERFILE }}" = "docker/ipfs.Dockerfile" ]]; then
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash
fi
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash > ${{ matrix.app }}-ipfs-hash
echo "List html directory"
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree .'
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree /usr/share/nginx/html'
- 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
- name: Publish dist as docker image (ghcr)
uses: docker/build-push-action@v3
if: ${{ github.event_name == 'pull_request' }}
if: ${{ github.event_name == 'pull_request' || (matrix.app == 'trading' && github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/v') ) }}
with:
context: .
file: ${{ env.DOCKERFILE }}
file: docker/node-outside-docker.Dockerfile
push: true
build-args: |
APP=${{ matrix.app }}
NODE_VERSION=${{ env.NODE_VERSION }}
ENV_NAME=${{ env.ENV_NAME }}
tags: |
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
- name: Publish dist to s3
uses: jakejarvis/s3-sync-action@master
if: ${{ github.event_name == 'push' }}
if: ${{ github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/v') }}
with:
args: --acl private --follow-symlinks --delete
env:
@@ -169,3 +169,56 @@ jobs:
with:
labels: ${{ matrix.app }}-preview
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,6 +2,7 @@
# compiled output
/dist
/dist-result
/tmp
/out-tsc
/tools/executors/**/*.js
-1
View File
@@ -7,5 +7,4 @@ __generated___
apps/static/src/assets/devnet-tranches.json
apps/static/src/assets/mainnet-tranches.json
apps/static/src/assets/stagnet3-tranches.json
apps/static/src/assets/testnet-tranches.json
+20
View File
@@ -0,0 +1,20 @@
.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
+55 -12
View File
@@ -103,25 +103,68 @@ 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.
# Docker & Vegacapsule
# 🐋 Hosting a console
## Docker
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).
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:
In order to run a container on port 3000:
```bash
docker run -p 3000:80 [TAG]
```
Images ending with `.dist` are to pack locally created transpiled HTML files into nginx container for non-compatible with yarn architectures like M1 Mac
## Build instructions
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
+1 -1
View File
@@ -2,7 +2,7 @@
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_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocket
NX_VEGA_URL=https://api.vega.xyz/query
NX_VEGA_URL=https://api.vega.community/graphql
NX_VEGA_ENV=MAINNET
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
-18
View File
@@ -1,18 +0,0 @@
# 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
@@ -10,6 +10,8 @@
"governance.proposal.updateMarket.minVoterBalance",
"governance.proposal.updateNetParam.minProposerBalance",
"governance.proposal.updateNetParam.minVoterBalance",
"governance.proposal.updateAsset.minProposerBalance",
"governance.proposal.updateAsset.minVoterBalance",
"reward.staking.delegation.maxPayoutPerEpoch",
"reward.staking.delegation.maxPayoutPerParticipant",
"reward.staking.delegation.minimumValidatorStake",
@@ -19,9 +21,6 @@
"validators.delegation.minAmount"
],
"fiveDecimal": [
"governance.proposal.updateAsset.minProposerBalance",
"governance.proposal.updateAsset.minVoterBalance",
"governance.proposal.updateAsset.requiredParticipation",
"market.fee.factors.infrastructureFee",
"market.fee.factors.makerFee",
"market.liquidity.bondPenaltyParameter",
@@ -77,6 +76,7 @@
"governance.proposal.updateNetParam.requiredMajority",
"governance.proposal.updateNetParam.requiredParticipation",
"governance.proposal.updateMarket.minProposerEquityLikeShare",
"governance.proposal.updateAsset.requiredParticipation",
"validators.vote.required"
],
"duration": [
@@ -138,7 +138,7 @@ context('Network parameters page', { tags: '@smoke' }, function () {
});
});
it('should list each network parameter displayed as a currency value with four decimals - in the correct format', function () {
it.skip('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) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
+14 -8
View File
@@ -1,13 +1,19 @@
NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n00.stagnet3.vega.xyz/websocket
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
NX_VEGA_NETWORKS='{"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_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
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.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_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_VEGA_GOVERNANCE_URL=https://stagnet1.governance.vega.xyz
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
NX_EXPLORER_ASSETS=1
+1 -8
View File
@@ -4,14 +4,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
NX_VEGA_ENV=CUSTOM
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
NX_VEGA_EXPLORER_URL=/
# 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
+3 -2
View File
@@ -5,7 +5,8 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-inter
NX_VEGA_ENV=DEVNET
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://dev.token.vega.xyz
NX_VEGA_GOVERNANCE_URL=https://dev.governance.vega.xyz
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_EXPLORER_URL=/
+7 -5
View File
@@ -1,9 +1,11 @@
# App configuration variables
NX_TENDERMINT_URL=https://be.explorer.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.explorer.vega.xyz/websocket
NX_TENDERMINT_URL=https://be.vega.community
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
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_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest/
NX_BLOCK_EXPLORER=https://be.vega.community/rest/
NX_ETHERSCAN_URL=https://etherscan.io
NX_VEGA_GOVERNANCE_URL=https://token.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
+2 -14
View File
@@ -1,14 +1,2 @@
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
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
# .env is stagnet1, so there are no overrides required
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET3":"https://stagnet3.explorer.vega.xyz"}'
-8
View File
@@ -1,8 +0,0 @@
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
+3 -2
View File
@@ -7,5 +7,6 @@ NX_VEGA_ENV=TESTNET
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://token.fairground.wtf
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
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,3 +11,4 @@ NX_VEGA_GOVERNANCE_URL=https://validator-testnet.governance.vega.xyz
NX_TENDERMINT_URL=https://tm-be.validators-testnet.vega.rocks
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
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,3 +5,4 @@ NX_VEGA_ENV=CUSTOM
NX_BLOCK_EXPLORER=
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
NX_VEGA_EXPLORER_URL=/
+1 -2
View File
@@ -35,12 +35,11 @@ Example configurations are provided here:
- [Devnet](./.env.devnet)
- [Capsule](./.env.capsule)
- [Testnet](./.env.testnet)
- [Stagnet3](./.env.stagnet3)
For convenience, you can boot the app injecting one of the configurations above by running:
```bash
yarn nx run explorer:serve --env={env} # e.g. stagnet3
yarn nx run explorer:serve --env={env} # e.g. stagnet1
```
There are a few different configuration options offered for this app:
+24 -2
View File
@@ -1,9 +1,18 @@
import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment';
import {
AppFailure,
NetworkLoader,
NodeGuard,
NodeSwitcherDialog,
useEnvironment,
useInitializeEnv,
useNodeSwitcherStore,
} from '@vegaprotocol/environment';
import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider';
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
import { RouterProvider } from 'react-router-dom';
import { router } from './routes/router-config';
import { t } from '@vegaprotocol/i18n';
const splashLoading = (
<Splash>
@@ -12,10 +21,23 @@ const splashLoading = (
);
function App() {
const { VEGA_URL } = useEnvironment();
const [nodeSwitcherOpen, setNodeSwitcherOpen] = useNodeSwitcherStore(
(store) => [store.dialogOpen, store.setDialogOpen]
);
return (
<TendermintWebsocketProvider>
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
<RouterProvider router={router} fallbackElement={splashLoading} />
<NodeGuard
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>
</TendermintWebsocketProvider>
);
@@ -1,13 +1,19 @@
import { NodeSwitcherDialog, useEnvironment } from '@vegaprotocol/environment';
import {
useEnvironment,
useNodeSwitcherStore,
} from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n';
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import { ExternalLink, Link } from '@vegaprotocol/ui-toolkit';
import { useMemo, useState } from 'react';
import { useMemo } from 'react';
import { ENV } from '../../config/env';
export const Footer = () => {
const { VEGA_URL, GIT_COMMIT_HASH, GIT_ORIGIN_URL } = useEnvironment();
const [nodeSwitcherOpen, setNodeSwitcherOpen] = useState(false);
const setNodeSwitcherOpen = useNodeSwitcherStore(
(store) => store.setDialogOpen
);
const { screenSize } = useScreenDimensions();
const showFullFeedbackLabel = useMemo(
() => ['md', 'lg', 'xl', 'xxl', 'xxxl'].includes(screenSize),
@@ -15,46 +21,40 @@ export const Footer = () => {
);
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">
{GIT_COMMIT_HASH && (
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
<p data-testid="git-commit-hash">
{t('Version')}:{' '}
<Link
href={
GIT_ORIGIN_URL
? `${GIT_ORIGIN_URL}/commit/${GIT_COMMIT_HASH}`
: undefined
}
target={GIT_ORIGIN_URL ? '_blank' : undefined}
>
{GIT_COMMIT_HASH}
</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>
<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">
{GIT_COMMIT_HASH && (
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
<p data-testid="git-commit-hash">
{t('Version')}:{' '}
<Link
href={
GIT_ORIGIN_URL
? `${GIT_ORIGIN_URL}/commit/${GIT_COMMIT_HASH}`
: undefined
}
target={GIT_ORIGIN_URL ? '_blank' : undefined}
>
{GIT_COMMIT_HASH}
</Link>
</p>
</div>
)}
<div className="flex pl-2 content-center">
<ExternalLink href={ENV.addresses.feedback}>
{showFullFeedbackLabel ? t('Share your feedback') : t('Feedback')}
</ExternalLink>
</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>
</footer>
<NodeSwitcherDialog
open={nodeSwitcherOpen}
setOpen={setNodeSwitcherOpen}
/>
</>
<div className="flex pl-2 content-center">
<ExternalLink href={ENV.addresses.feedback}>
{showFullFeedbackLabel ? t('Share your feedback') : t('Feedback')}
</ExternalLink>
</div>
</div>
</footer>
);
};
@@ -14,10 +14,72 @@ import {
SettlementAssetInfoPanel,
} from '@vegaprotocol/market-info';
import { MarketInfoTable } from '@vegaprotocol/market-info';
import type { DataSourceDefinition } from '@vegaprotocol/types';
import isEqual from 'lodash/isEqual';
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
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 = [
{
title: t('Key details'),
@@ -95,22 +157,7 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
<LiquidityPriceRangeInfoPanel market={market} noBorder={false} />
),
},
{
title: t('Settlement Oracle'),
content: (
<OracleInfoPanel
noBorder={false}
market={market}
type="settlementData"
/>
),
},
{
title: t('Termination Oracle'),
content: (
<OracleInfoPanel noBorder={false} market={market} type="termination" />
),
},
...oraclePanels,
];
return (
@@ -12,7 +12,10 @@ import { useLayoutEffect, useMemo, useRef, useState } from 'react';
import type { RowClickedEvent } from 'ag-grid-community';
import { getDateTimeFormat } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers';
import {
NetworkParams,
useNetworkParams,
} from '@vegaprotocol/network-parameters';
import { ProposalStateMapping } from '@vegaprotocol/types';
import BigNumber from 'bignumber.js';
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
@@ -1,3 +1,5 @@
import { Icon } from '@vegaprotocol/ui-toolkit';
// https://github.com/vegaprotocol/vega/blob/develop/core/blockchain/response.go
export const ErrorCodes = new Map([
[51, 'Transaction failed validation'],
@@ -28,7 +30,11 @@ export const ChainResponseCode = ({
}: ChainResponseCodeProps) => {
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';
// Hack for batches with many errors - see https://github.com/vegaprotocol/vega/issues/7245
@@ -36,7 +42,7 @@ export const ChainResponseCode = ({
error && error.length > 100 ? error.replace(/,/g, ',\r\n') : error;
return (
<div title={`Response code: ${code} - ${label}`} className="inline-block">
<div title={`Response code: ${code} - ${label}`} className=" inline-block">
<span
className="mr-2"
aria-label={isSuccess ? 'Success' : 'Warning'}
@@ -4,6 +4,7 @@ import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint
import { TxDetailsShared } from './shared/tx-details-shared';
import { TableCell, TableRow, TableWithTbody } from '../../table';
import ProposalLink from '../../links/proposal-link/proposal-link';
import { VoteIcon } from '../../vote-icon/vote-icon';
interface TxProposalVoteProps {
txData: BlockExplorerTransactionResult | undefined;
@@ -30,27 +31,22 @@ export const TxProposalVote = ({
return <>{t('Awaiting Block Explorer transaction details')}</>;
}
const vote = txData.command.voteSubmission.value ? '👍' : '👎';
const vote = txData.command.voteSubmission.value === 'VALUE_YES';
return (
<TableWithTbody className="mb-8" allowWrap={true}>
<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">
<TableCell>{t('Proposal details')}</TableCell>
<TableCell>
<ProposalLink id={txData.command.voteSubmission.proposalId} />
</TableCell>
</TableRow>
<TableRow modifier="bordered">
<TableCell>{t('Proposal')}</TableCell>
<TableCell>{txData.command.voteSubmission.proposalId}</TableCell>
</TableRow>
<TableRow modifier="bordered">
<TableCell>{t('Vote')}</TableCell>
<TableCell>{vote}</TableCell>
<TableCell>
<VoteIcon vote={vote} />
</TableCell>
</TableRow>
</TableWithTbody>
);
@@ -1,5 +1,6 @@
import { t } from '@vegaprotocol/i18n';
import type { components } from '../../../types/explorer';
import { VoteIcon } from '../vote-icon/vote-icon';
interface TxOrderTypeProps {
orderType: string;
@@ -137,12 +138,15 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
let type = displayString[orderType] || orderType;
let colours =
'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-150';
'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-250';
// This will get unwieldy and should probably produce a different colour of tag
if (type === 'Chain Event' && !!command?.chainEvent) {
type = getLabelForChainEvent(command.chainEvent);
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') {
if (command && !!command.proposalSubmission) {
type = getLabelForProposal(command.proposalSubmission);
@@ -150,6 +154,16 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
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') {
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('tx-type')).toHaveTextContent('testType');
expect(screen.getByTestId('tx-block')).toHaveTextContent('1');
expect(screen.getByTestId('tx-success')).toHaveTextContent('Success: ✅');
expect(screen.getByTestId('tx-success')).toHaveTextContent('Success');
});
});
@@ -31,7 +31,7 @@ export const TxsInfiniteListItem = ({
return (
<div
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 py-2"
className="flex items-center h-full border-t border-neutral-600 dark:border-neutral-800 txs-infinite-list-item grid grid-cols-10"
>
<div
className="text-sm col-span-10 md:col-span-3 leading-none"
@@ -83,7 +83,7 @@ export const TxsInfiniteListItem = ({
data-testid="tx-success"
>
<span className="md:hidden uppercase text-vega-dark-300">
Success:&nbsp;
Success&nbsp;
</span>
{isNumber(code) ? (
<ChainResponseCode code={code} hideLabel={true} />
@@ -0,0 +1,37 @@
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');
});
});
@@ -0,0 +1,40 @@
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>
);
}
@@ -1,6 +1,6 @@
import { proposalsDataProvider } from '@vegaprotocol/proposals';
import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { ProposalsTable } from '../../components/proposals/proposals-table';
import { RouteTitle } from '../../components/route-title';
@@ -1,5 +1,5 @@
import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
import { useState } from 'react';
import { useParams } from 'react-router-dom';
@@ -4,7 +4,7 @@ import { marketsProvider } from '@vegaprotocol/market-list';
import { RouteTitle } from '../../components/route-title';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { MarketsTable } from '../../components/markets/markets-table';
export const MarketsPage = () => {
@@ -1,5 +1,5 @@
import { render, screen } from '@testing-library/react';
import type { NetworkParamsQuery } from '@vegaprotocol/react-helpers';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import { NetworkParametersTable } from './network-parameters';
describe('NetworkParametersTable', () => {
@@ -13,14 +13,15 @@ import {
import { t } from '@vegaprotocol/i18n';
import { RouteTitle } from '../../components/route-title';
import orderBy from 'lodash/orderBy';
import { useNetworkParamsQuery } from '@vegaprotocol/react-helpers';
import type { NetworkParamsQuery } from '@vegaprotocol/react-helpers';
import { useNetworkParamsQuery } from '@vegaprotocol/network-parameters';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import { useScrollToLocation } from '../../hooks/scroll-to-location';
import { useDocumentTitle } from '../../hooks/use-document-title';
const PERCENTAGE_PARAMS = [
'governance.proposal.asset.requiredMajority',
'governance.proposal.asset.requiredParticipation',
'governance.proposal.updateAsset.requiredParticipation',
'governance.proposal.freeform.requiredMajority',
'governance.proposal.freeform.requiredParticipation',
'governance.proposal.market.requiredMajority',
@@ -53,6 +54,8 @@ const BIG_NUMBER_PARAMS = [
'governance.proposal.asset.minProposerBalance',
'governance.proposal.market.minProposerBalance',
'governance.proposal.market.minVoterBalance',
'governance.proposal.updateAsset.minProposerBalance',
'governance.proposal.updateAsset.minVoterBalance',
];
export const NetworkParameterRow = ({
@@ -1,8 +1,5 @@
import { t } from '@vegaprotocol/i18n';
import {
useDataProvider,
useScreenDimensions,
} from '@vegaprotocol/react-helpers';
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import { useMemo } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { SubHeading } from '../../../components/sub-heading';
@@ -16,6 +13,7 @@ import { aggregatedAccountsDataProvider } from '@vegaprotocol/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 } = useParams<{ party: string }>();
+9
View File
@@ -32,6 +32,11 @@
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);
@@ -55,3 +60,7 @@
--ag-row-hover-color: theme(colors.neutral[800]);
--ag-font-size: 12px;
}
.voteicon svg {
vertical-align: baseline;
}
+2 -2
View File
@@ -13,7 +13,7 @@ NX_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
@@ -30,6 +30,6 @@ CYPRESS_TRUNCATED_VEGA_PUBLIC_KEY2=7f9cf0…c25535
CYPRESS_VEGA_ENV=CUSTOM
CYPRESS_VEGA_PUBLIC_KEY=02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65
CYPRESS_VEGA_PUBLIC_KEY2=7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535
CYPRESS_VEGA_TOKEN_URL=https://token.fairground.wtf
CYPRESS_VEGA_TOKEN_URL=https://governance.fairground.wtf
CYPRESS_VEGA_WALLET_URL=http://localhost:1789
CYPRESS_VEGA_WALLET_API_TOKEN=
+1 -1
View File
@@ -1,5 +1,5 @@
# App configuration variables
NX_VEGA_ENV=MAINNET
NX_VEGA_URL=https://api.vega.xyz/query
NX_VEGA_URL=https://api.vega.community/graphql
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://etherscan.io
-5
View File
@@ -1,5 +0,0 @@
# 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
@@ -2,14 +2,14 @@ import {
navigateTo,
waitForSpinner,
navigation,
turnTelemetryOff,
} from '../../support/common.functions';
import {
convertUnixTimestampToDateformat,
createRawProposal,
createTenDigitUnixTimeStampForSpecifiedDays,
enterUniqueFreeFormProposalBody,
generateFreeFormProposalTitle,
getGovernanceProposalDateFormatForSpecifiedDays,
getDateFormatForSpecifiedDays,
getProposalIdFromList,
getProposalInformationFromTable,
getSubmittedProposalFromProposalList,
@@ -23,6 +23,7 @@ import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../../../governan
import { ethereumWalletConnect } from '../../../../governance-e2e/src/support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../../../governance-e2e/src/support/wallet-teardown.functions';
import type { testFreeformProposal } from '../../support/common-interfaces';
import { formatDateWithLocalTimezone } from '@vegaprotocol/utils';
const proposalVoteProgressForPercentage =
'[data-testid="vote-progress-indicator-percentage-for"]';
@@ -50,6 +51,7 @@ describe(
beforeEach('visit proposals tab', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
@@ -99,20 +101,22 @@ describe(
getSubmittedProposalFromProposalList(proposalTitle).within(() =>
cy.get(viewProposalButton).click()
);
convertUnixTimestampToDateformat(proposalTimeStamp).then(
(closingDate) => {
getProposalInformationFromTable('Closes on')
.contains(closingDate)
.should('be.visible');
}
);
getGovernanceProposalDateFormatForSpecifiedDays(0).then(
(proposalDate) => {
getProposalInformationFromTable('Proposed on')
.contains(proposalDate)
.should('be.visible');
}
);
cy.wrap(
formatDateWithLocalTimezone(new Date(proposalTimeStamp * 1000))
).then((closingDate) => {
getProposalInformationFromTable('Closes on')
.contains(closingDate)
.should('be.visible');
});
cy.wrap(
formatDateWithLocalTimezone(
new Date(createTenDigitUnixTimeStampForSpecifiedDays(0) * 1000)
)
).then((proposalDate) => {
getProposalInformationFromTable('Proposed on')
.contains(proposalDate)
.should('be.visible');
});
});
it('Newly created proposal details - shows default status set to fail', function () {
@@ -155,18 +159,16 @@ describe(
cy.getByTestId('vote-buttons').contains('against').should('be.visible');
cy.getByTestId('vote-buttons').contains('for').should('be.visible');
voteForProposal('for');
getGovernanceProposalDateFormatForSpecifiedDays(0, 'shortMonth').then(
(votedDate) => {
// 3001-VOTE-051
// 3001-VOTE-093
cy.contains('You voted:')
.siblings()
.contains('For')
.siblings()
.contains(votedDate)
.should('be.visible');
}
);
getDateFormatForSpecifiedDays(0).then((votedDate) => {
// 3001-VOTE-051
// 3001-VOTE-093
cy.contains('You voted:')
.siblings()
.contains('For')
.siblings()
.contains(votedDate)
.should('be.visible');
});
cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072
.contains('100.00%')
.and('be.visible');
@@ -2,6 +2,7 @@
import {
navigateTo,
navigation,
turnTelemetryOff,
waitForSpinner,
} from '../../support/common.functions';
import {
@@ -37,6 +38,7 @@ context(
beforeEach('visit proposals', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
@@ -20,6 +20,7 @@ import {
navigateTo,
navigation,
closeDialog,
turnTelemetryOff,
} from '../../support/common.functions';
import {
clickOnValidatorFromList,
@@ -85,6 +86,7 @@ context(
beforeEach('visit governance tab', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
@@ -2,6 +2,7 @@ import {
closeDialog,
navigateTo,
navigation,
turnTelemetryOff,
waitForSpinner,
} from '../../support/common.functions';
import {
@@ -77,6 +78,7 @@ context(
beforeEach('visit governance tab', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
@@ -2,6 +2,7 @@ import type { testFreeformProposal } from '../../support/common-interfaces';
import {
navigateTo,
navigation,
turnTelemetryOff,
waitForSpinner,
} from '../../support/common.functions';
import {
@@ -36,6 +37,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
beforeEach('visit proposals tab', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
@@ -1,6 +1,7 @@
import {
navigateTo,
navigation,
turnTelemetryOff,
waitForSpinner,
} from '../../support/common.functions';
import {
@@ -26,6 +27,7 @@ const rewardsTimeOut = { timeout: 60000 };
context('rewards - flow', { tags: '@slow' }, function () {
before('set up environment to allow rewards', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.visit('/');
waitForSpinner();
depositAsset(vegaAssetAddress, '1000', 18);
@@ -7,6 +7,7 @@ import {
waitForSpinner,
navigateTo,
navigation,
turnTelemetryOff,
} from '../../support/common.functions';
import {
clickOnValidatorFromList,
@@ -67,6 +68,7 @@ context(
'teardown wallet & drill into a specific validator',
function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
@@ -252,10 +254,10 @@ context(
waitForBeginningOfEpoch();
cy.getByTestId(stakeValidatorListStakePercentage).should(
'have.text',
'100%'
'50.02%'
);
navigateTo(navigation.validators);
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%');
}
);
@@ -4,6 +4,7 @@ import {
waitForSpinner,
navigateTo,
navigation,
turnTelemetryOff,
} from '../../support/common.functions';
import {
stakingPageAssociateTokens,
@@ -54,6 +55,7 @@ context(
'teardown wallet & drill into a specific validator',
function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
@@ -1,6 +1,7 @@
import {
navigateTo,
navigation,
turnTelemetryOff,
waitForSpinner,
} from '../../support/common.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
@@ -29,6 +30,8 @@ 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 usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0';
const usdcSymbol = 'tUSDC';
@@ -53,6 +56,7 @@ context(
beforeEach('Navigate to withdrawal page', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload();
waitForSpinner();
navigateTo(navigation.withdraw);
@@ -149,7 +153,6 @@ context(
});
});
// Skipping because of bug #1857
it('Able to withdraw asset: -eth wallet not connected', function () {
const ethWalletAddress = Cypress.env('ethWalletPublicKey');
cy.reload();
@@ -187,8 +190,26 @@ context(
.should('have.attr', 'href')
.and('contain', 'https://sepolia.etherscan.io/address/');
cy.get(tableCreatedTimeStamp).should('not.be.empty');
cy.getByTestId(completeWithdrawalButton).click();
// Unable to complete withdrawal in Capsule
});
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,7 +239,10 @@ context(
});
function waitForAssetsDisplayed(expectedAsset: string) {
cy.getByTestId('currency-title').should('contain.text', expectedAsset);
cy.getByTestId('currency-title', txTimeout).should(
'contain.text',
expectedAsset
);
}
}
);
@@ -27,7 +27,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
cy.getByTestId('app-announcement').should('not.exist');
});
it('should show open or enacted proposals with proposal summary', function () {
it('should show open or enacted proposals without proposal summary', function () {
cy.get('body').then(($body) => {
if (!$body.find('[data-testid="proposals-list-item"]').length) {
cy.createMarket();
@@ -43,12 +43,6 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
.invoke('text')
.should('not.be.empty');
cy.getByTestId('proposal-type').invoke('text').should('not.be.empty');
cy.getByTestId('proposal-description')
.invoke('text')
.should('not.be.empty');
cy.getByTestId('proposal-details')
.invoke('text')
.should('not.be.empty');
cy.getByTestId('proposal-status')
.invoke('text')
.should('not.be.empty');
@@ -167,7 +161,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
cy.getByTestId('menu-drawer').should('be.visible');
});
it('should have link for proposal page', function () {
it.skip('should have link for proposal page', function () {
cy.getByTestId('menu-drawer').within(() => {
cy.get('[href="/proposals"]')
.should('exist')
@@ -54,7 +54,7 @@ context(
});
});
it('should be able to see button for - new proposal', function () {
it.skip('should be able to see button for - new proposal', function () {
// 3001-VOTE-002
cy.get(newProposalLink)
.should('be.visible')
@@ -63,7 +63,7 @@ context(
.and('equal', '/proposals/propose');
});
it('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () {
it.skip('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () {
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.get(connectToVegaWalletButton)
.should('be.visible')
@@ -101,15 +101,15 @@ context(
);
cy.getByTestId('protocol-upgrade-proposal-release-tag').should(
'have.text',
'Vega release tagv1'
'Vega release tag: v1'
);
cy.getByTestId('protocol-upgrade-proposal-block-height').should(
'have.text',
'Upgrade block height2015942'
'Upgrade block height: 2015942'
);
cy.getByTestId('protocol-upgrade-proposal-status').should(
'have.text',
'Approved'
'Approved by validators '
);
});
});
@@ -136,7 +136,7 @@ context(
);
cy.getByTestId('protocol-upgrade-state').should(
'have.text',
'Approved'
'Approved by validators'
);
cy.getByTestId('protocol-upgrade-release-tag').should(
'have.text',
@@ -3,6 +3,7 @@
import {
navigateTo,
navigation,
turnTelemetryOff,
waitForSpinner,
} from '../../support/common.functions';
import {
@@ -26,6 +27,7 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
beforeEach('visit home page', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.visit('/');
waitForSpinner();
cy.connectPublicKey(vegaWalletPubKey);
@@ -44,7 +46,7 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
.and('contain.text', 'USDC (fake)');
});
it('Unable to submit proposal with public key', function () {
it.skip('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.`;
navigateTo(navigation.proposals);
@@ -13,7 +13,6 @@ context(
{ tags: '@regression' },
function () {
before('navigate to rewards page', function () {
cy.clearLocalStorage();
cy.visit('/');
navigateTo(navigation.rewards);
});
@@ -29,11 +29,10 @@ const performancePenaltyToolTip = '[data-testid="performance-penalty-tooltip"]';
const overstakedPenaltyToolTip = '[data-testid="overstaked-penalty-tooltip"]';
const totalPenaltyToolTip = '[data-testid="total-penalty-tooltip"]';
const epochCountDown = '[data-testid="epoch-countdown"]';
const stakeNumberRegex = /^\d*\.?\d*$/;
const stakeNumberRegex = /^\d{1,3}(,\d{3})*(\.\d+)?$/;
context('Validators Page - verify elements on page', function () {
before('navigate to validators page', function () {
cy.clearAllLocalStorage();
cy.visit('/validators');
});
@@ -85,13 +84,13 @@ context('Validators Page - verify elements on page', function () {
cy.get(stakedByOperatorToolTip)
.invoke('text')
.should('contain', 'Staked by operator: 0.00');
.should('contain', 'Staked by operator: 3,000.00');
cy.get(stakedByDelegatesToolTip)
.invoke('text')
.should('contain', 'Staked by delegates: 0.00');
cy.get(totalStakedToolTip)
.invoke('text')
.should('contain', 'Total stake: 0.00');
.should('contain', 'Total stake: 3,000.00');
});
it('Should be able to see validator normalised voting power', function () {
@@ -107,10 +106,10 @@ context('Validators Page - verify elements on page', function () {
cy.get(unnormalisedVotingPowerToolTip)
.invoke('text')
.should('contain', 'Unnormalised voting power: 0.00%');
.should('contain', 'Unnormalised voting power: 20.00%');
cy.get(normalisedVotingPowerToolTip)
.invoke('text')
.should('contain', 'Normalised voting power: 0.10%');
.should('contain', 'Normalised voting power: 50.00%');
});
// 2002-SINC-018
@@ -127,13 +126,13 @@ context('Validators Page - verify elements on page', function () {
cy.get(performancePenaltyToolTip)
.invoke('text')
.should('contain', 'Performance penalty: 100.00%');
.should('contain', 'Performance penalty: 0.00%');
cy.get(overstakedPenaltyToolTip)
.invoke('text')
.should('contain', 'Overstaked penalty:'); // value not asserted due to #2886
.should('contain', 'Overstaked penalty: 60.00%'); // value not asserted due to #2886
cy.get(totalPenaltyToolTip)
.invoke('text')
.should('contain', 'Total penalties: 0.00%');
.should('contain', 'Total penalties: 60.00%');
});
it('Should be able to see validator pending stake', function () {
@@ -35,7 +35,6 @@ context(
{ tags: '@regression' },
() => {
before('visit token home page', () => {
cy.clearAllLocalStorage();
cy.visit('/');
cy.get(walletContainer, { timeout: 60000 }).should('be.visible');
});
@@ -12,7 +12,6 @@ context(
{ tags: '@smoke' },
function () {
before('navigate to withdrawals page', function () {
cy.clearAllLocalStorage();
cy.visit('/');
navigateTo(navigation.withdraw);
});
@@ -90,3 +90,10 @@ export function verifyEthWalletAssociatedBalance(amount: string) {
export function closeDialog() {
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,3 +1,4 @@
import { format } from 'date-fns';
import { closeDialog, navigateTo, navigation } from './common.functions';
import { ensureSpecifiedUnstakedTokensAreAssociated } from './staking.functions';
@@ -15,35 +16,6 @@ const newProposalSubmitButton = '[data-testid="proposal-submit"]';
const epochTimeout = Cypress.env('epochTimeout');
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(
durationDays: number
) {
@@ -52,6 +24,13 @@ export function createTenDigitUnixTimeStampForSpecifiedDays(
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) {
cy.fixture('/proposals/raw.json').then((rawProposal) => {
rawProposal.terms.closingTimestamp = timestamp;
@@ -104,16 +83,6 @@ export function getProposalIdFromList(proposalTitle: string) {
});
}
export function getGovernanceProposalDateFormatForSpecifiedDays(
days: number,
shortOrLong?: string
) {
return convertUnixTimestampToDateformat(
createTenDigitUnixTimeStampForSpecifiedDays(days),
shortOrLong
);
}
export function getProposalInformationFromTable(heading: string) {
return cy.get(proposalInformationTableRows).contains(heading).siblings();
}
+6
View File
@@ -11,6 +11,7 @@ import './proposal.functions.ts';
import registerCypressGrep from '@cypress/grep';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { chainIdQuery, statisticsQuery } from '@vegaprotocol/mock';
import { turnTelemetryOff } from './common.functions.ts';
registerCypressGrep();
// Hide fetch/XHR requests - They create a lot of noise in command log
@@ -24,9 +25,14 @@ if (!app.document.head.querySelector('[data-hide-command-log-request]')) {
}
before(() => {
cy.clearLocalStorage();
// // Ensuring the telemetry modal doesn't disrupt the tests
turnTelemetryOff();
// Mock chainId fetch which happens on every page for wallet connection
cy.mockGQL((req) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
// Self stake validators so they are displayed
cy.validatorsSelfDelegate();
});
@@ -89,6 +89,6 @@ export function mockNetworkUpgradeProposal() {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Nodes', nodeData);
aliasGQLQuery(req, 'Proposals', proposalsData);
aliasGQLQuery(req, 'ProtocolUpgrades', upgradeProposalsData);
aliasGQLQuery(req, 'ProtocolUpgradeProposals', upgradeProposalsData);
});
}
+6 -6
View File
@@ -1,18 +1,18 @@
# App configuration variables
NX_VEGA_ENV=STAGNET3
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET1
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
NX_VEGA_URL=https://api.n00.stagnet1.vega.xyz/graphql
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_FAIRGROUND=false
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","STAGNET1":"https://stagnet1.governance.vega.xyz","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz"}'
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
+2 -2
View File
@@ -3,7 +3,7 @@ NX_VEGA_ENV=CUSTOM
NX_ETHEREUM_PROVIDER_URL=http://localhost:8545
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_FAIRGROUND=false
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz"}'
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
NX_VEGA_CONFIG_URL=''
@@ -16,7 +16,7 @@ NX_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
#Test configuration variables
CYPRESS_FAIRGROUND=false
+2 -2
View File
@@ -2,7 +2,7 @@
NX_VEGA_ENV=DEVNET
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
NX_VEGA_URL=https://api.n00.devnet1.vega.xyz/graphql
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz"}'
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
@@ -10,4 +10,4 @@ NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
+2 -2
View File
@@ -1,8 +1,8 @@
# App configuration variables
NX_VEGA_ENV=MAINNET
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
NX_VEGA_URL=https://api.vega.xyz/query
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_URL=https://api.vega.community/graphql
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz"}'
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
+2 -2
View File
@@ -1,10 +1,10 @@
# App configuration variables
NX_VEGA_URL=https://api.n00.stagnet1.vega.xyz/graphql
NX_VEGA_ENV=STAGNET1
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","STAGNET1":"https://stagnet1.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","STAGNET1":"https://stagnet1.governance.vega.xyz","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz"}'
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
-11
View File
@@ -1,11 +0,0 @@
# App configuration variables
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET3
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
+1 -1
View File
@@ -2,7 +2,7 @@
NX_VEGA_ENV=TESTNET
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz"}'
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
+1 -1
View File
@@ -3,7 +3,7 @@ NX_VEGA_ENV=VALIDATOR_TESTNET
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz"}'
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
+1 -2
View File
@@ -27,12 +27,11 @@ Example configurations are provided here:
- [Mainnet](./.env.mainnet)
- [Devnet](./.env.devnet)
- [Testnet](./.env.testnet)
- [Stagnet3](./.env.stagnet3)
For convenience, you can boot the app injecting one of the configurations above by running:
```bash
yarn nx run governance:serve --env={env} # e.g. stagnet3
yarn nx run governance:serve --env={env} # e.g. stagnet1
```
There are a few different configuration options offered for this app:
+5
View File
@@ -0,0 +1,5 @@
function ReactMarkdown({ children }) {
return <div>{children}</div>;
}
export default ReactMarkdown;
+9 -3
View File
@@ -58,9 +58,15 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
token.decimals(),
]);
const totalSupply = toBigNum(supply, decimals);
const totalWallet = toBigNum(totalAssociatedWallet, decimals);
const totalVesting = toBigNum(totalAssociatedVesting, decimals);
const totalSupply = toBigNum(supply.toString(), decimals);
const totalWallet = toBigNum(
totalAssociatedWallet.toString(),
decimals
);
const totalVesting = toBigNum(
totalAssociatedVesting.toString(),
decimals
);
appDispatch({
type: AppStateActionType.SET_TOKEN,
+98 -29
View File
@@ -2,7 +2,6 @@ import './i18n';
import React, { useEffect } from 'react';
import * as Sentry from '@sentry/react';
import { Integrations } from '@sentry/tracing';
import { BrowserRouter as Router, useLocation } from 'react-router-dom';
import { AppLoader } from './app-loader';
import { NetworkInfo } from '@vegaprotocol/network-info';
@@ -20,23 +19,39 @@ import type { EthereumConfig } from '@vegaprotocol/web3';
import {
createConnectors,
useEthTransactionManager,
useEthTransactionUpdater,
useEthWithdrawApprovalsManager,
useWeb3ConnectStore,
} from '@vegaprotocol/web3';
import { Web3Provider } from '@vegaprotocol/web3';
import { VegaWalletDialogs } from './components/vega-wallet-dialogs';
import { VegaWalletProvider } from '@vegaprotocol/wallet';
import {
useVegaTransactionManager,
useVegaTransactionUpdater,
VegaWalletProvider,
} from '@vegaprotocol/wallet';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { useEthereumConfig } from '@vegaprotocol/web3';
import {
useEnvironment,
NetworkLoader,
useInitializeEnv,
NodeGuard,
AppFailure,
NodeSwitcherDialog,
useNodeSwitcherStore,
} from '@vegaprotocol/environment';
import { ENV } from './config';
import type { InMemoryCacheConfig } from '@apollo/client';
import { WithdrawalDialog } from '@vegaprotocol/withdraws';
import { SplashLoader } from './components/splash-loader';
import { ToastsManager } from './toasts-manager';
import {
TelemetryDialog,
TELEMETRY_ON,
} from './components/telemetry-dialog/telemetry-dialog';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
import { useTranslation } from 'react-i18next';
const cache: InMemoryCacheConfig = {
typePolicies: {
@@ -81,7 +96,10 @@ const Web3Container = ({
providerUrl: string;
}) => {
const InitializeHandlers = () => {
useVegaTransactionManager();
useVegaTransactionUpdater();
useEthTransactionManager();
useEthTransactionUpdater();
useEthWithdrawApprovalsManager();
return null;
};
@@ -135,10 +153,12 @@ const Web3Container = ({
<NetworkInfo />
</footer>
</AppLayout>
<ToastsManager />
<InitializeHandlers />
<VegaWalletDialogs />
<TransactionModal />
<WithdrawalDialog />
<TelemetryDialog />
</>
</BalanceManager>
</AppLoader>
@@ -163,58 +183,107 @@ const ScrollToTop = () => {
return null;
};
const removeQueryParams = (url: string) => {
return url.split('?')[0];
};
const AppContainer = () => {
const { config, loading, error } = useEthereumConfig();
const { VEGA_ENV, GIT_COMMIT_HASH, GIT_BRANCH, ETHEREUM_PROVIDER_URL } =
useEnvironment();
const {
VEGA_ENV,
VEGA_URL,
GIT_COMMIT_HASH,
GIT_BRANCH,
ETHEREUM_PROVIDER_URL,
} = useEnvironment();
const [telemetryOn] = useLocalStorage(TELEMETRY_ON);
const { t } = useTranslation();
const [nodeSwitcherOpen, setNodeSwitcher] = useNodeSwitcherStore((store) => [
store.dialogOpen,
store.setDialogOpen,
]);
useEffect(() => {
if (ENV.dsn) {
if (ENV.dsn && telemetryOn) {
Sentry.init({
dsn: ENV.dsn,
integrations: [new Integrations.BrowserTracing()],
tracesSampleRate: 0.1,
enabled: true,
environment: VEGA_ENV,
release: GIT_COMMIT_HASH,
beforeSend(event) {
if (event.request?.url?.includes('/claim?')) {
return {
...event,
request: {
...event.request,
url: event.request?.url.split('?')[0],
},
};
}
return event;
const requestUrl = event.request?.url;
const transaction = event.transaction;
const updatedRequest =
requestUrl && requestUrl.includes('/test?')
? { ...event.request, url: removeQueryParams(requestUrl) }
: event.request;
const updatedTransaction =
transaction && transaction.includes('/test?')
? removeQueryParams(transaction)
: transaction;
const updatedBreadcrumbs = event.breadcrumbs?.map((breadcrumb) => {
if (
breadcrumb.type === 'navigation' &&
breadcrumb.data?.to?.includes('/test?')
) {
return {
...breadcrumb,
data: {
...breadcrumb.data,
to: removeQueryParams(breadcrumb.data.to),
},
};
}
return breadcrumb;
});
return {
...event,
request: updatedRequest,
transaction: updatedTransaction,
breadcrumbs: updatedBreadcrumbs ?? event.breadcrumbs,
};
},
});
Sentry.setTag('branch', GIT_BRANCH);
Sentry.setTag('commit', GIT_COMMIT_HASH);
} else {
Sentry.close();
}
}, [GIT_COMMIT_HASH, GIT_BRANCH, VEGA_ENV]);
}, [GIT_COMMIT_HASH, GIT_BRANCH, VEGA_ENV, telemetryOn]);
return (
<Router>
<ScrollToTop />
<AppStateProvider>
<div className="grid min-h-full text-white">
<AsyncRenderer<EthereumConfig | null>
loading={loading}
data={config}
error={error}
render={(cnf) =>
cnf && (
<Web3Container
chainId={Number(cnf.chain_id)}
providerUrl={ETHEREUM_PROVIDER_URL}
/>
)
<NodeGuard
skeleton={<div>{t('Loading')}</div>}
failure={
<AppFailure title={t('NodeUnsuitable', { url: VEGA_URL })} />
}
/>
>
<AsyncRenderer<EthereumConfig | null>
loading={loading}
data={config}
error={error}
render={(cnf) =>
cnf && (
<Web3Container
chainId={Number(cnf.chain_id)}
providerUrl={ETHEREUM_PROVIDER_URL}
/>
)
}
/>
</NodeGuard>
</div>
</AppStateProvider>
<NodeSwitcherDialog open={nodeSwitcherOpen} setOpen={setNodeSwitcher} />
</Router>
);
};
@@ -23,6 +23,7 @@ export const ConnectToVega = () => {
openVegaWalletDialog();
}}
data-testid="connect-to-vega-wallet-btn"
variant="primary"
>
{t('connectVegaWallet')}
</Button>
@@ -23,7 +23,7 @@ export const Heading = ({
})}
>
<h1
className={classNames('font-alpha calt text-5xl', {
className={classNames('font-alpha calt text-5xl break-words', {
'mt-0': !marginTop,
'mb-0': !marginBottom,
})}
+21 -1
View File
@@ -11,11 +11,26 @@ import {
NavigationLink,
NavigationList,
NavigationTrigger,
Icon,
} from '@vegaprotocol/ui-toolkit';
import { EthWallet } from '../eth-wallet';
import { VegaWallet } from '../vega-wallet';
import { useLocation, useMatch } from 'react-router-dom';
import { useEffect } from 'react';
import { useTelemetryDialog } from '../telemetry-dialog/telemetry-dialog';
export const SettingsLink = () => {
const { open, isOpen, close } = useTelemetryDialog();
return (
<button
type="button"
onClick={() => (isOpen ? close() : open())}
aria-label="Open Telemetry Settings"
>
<Icon name="cog" className="w-5 h-5 mr-2" />
</button>
);
};
export const Nav = ({ theme }: Pick<NavigationProps, 'theme'>) => {
const { t } = useTranslation();
@@ -42,7 +57,12 @@ export const Nav = ({ theme }: Pick<NavigationProps, 'theme'>) => {
));
return (
<Navigation appName="Governance" theme={theme} breakpoints={[458, 959]}>
<Navigation
appName="Governance"
theme={theme}
breakpoints={[458, 959]}
actions={<SettingsLink />}
>
<NavigationList
className="[.drawer-content_&]:border-b [.drawer-content_&]:border-b-vega-light-200 dark:[.drawer-content_&]:border-b-vega-dark-200 [.drawer-content_&]:pb-8 [.drawer-content_&]:mb-2"
hide={[NavigationBreakpoint.Small]}
@@ -0,0 +1,53 @@
import { renderHook, act } from '@testing-library/react';
import { useTelemetryDialog, TELEMETRY_ON } from './telemetry-dialog';
describe('useTelemetryDialog', () => {
beforeEach(() => {
localStorage.clear();
});
it('should have the correct initial state based on localStorage', () => {
localStorage.setItem(TELEMETRY_ON, 'true');
const { result } = renderHook(() => useTelemetryDialog());
expect(result.current.isOpen).toBe(false);
expect(result.current.telemetryAccepted).toBe(true);
});
it('should update localStorage and the telemetryAccepted state when setTelemetryAccepted is called', () => {
const { result } = renderHook(() => useTelemetryDialog());
act(() => {
result.current.setTelemetryAccepted(true);
});
expect(result.current.telemetryAccepted).toBe(true);
expect(localStorage.getItem(TELEMETRY_ON)).toBe('true');
});
it('should update localStorage and the isOpen state when close is called', () => {
const { result } = renderHook(() => useTelemetryDialog());
act(() => {
result.current.close();
});
expect(result.current.isOpen).toBe(false);
});
it('should update the isOpen state when open is called', () => {
const { result } = renderHook(() => useTelemetryDialog());
act(() => {
result.current.open();
});
expect(result.current.isOpen).toBe(true);
});
it('should open the dialog if TELEMETRY_ON is not set', () => {
const { result } = renderHook(() => useTelemetryDialog());
expect(result.current.isOpen).toBe(true);
});
});
@@ -0,0 +1,102 @@
import { create } from 'zustand';
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
import { Dialog, Icon, Button } from '@vegaprotocol/ui-toolkit';
import { Networks, useEnvironment } from '@vegaprotocol/environment';
type TelemetryDialogState = {
isOpen: boolean;
open: () => void;
close: () => void;
};
const useTelemetryDialogStore = create<TelemetryDialogState>((set) => ({
isOpen: false,
open: () => set({ isOpen: true }),
close: () => set({ isOpen: false }),
}));
export const TELEMETRY_ON = 'vega_telemetry_on';
export const useTelemetryDialog = () => {
const [telemetryOn, setTelemetryOn] = useLocalStorage(TELEMETRY_ON);
const { VEGA_ENV } = useEnvironment();
const isMainnet = VEGA_ENV === Networks.MAINNET;
const defaultTelemetryAccepted = isMainnet ? 'false' : 'true';
const { isOpen, open, close } = useTelemetryDialogStore();
useEffect(() => {
if (telemetryOn === null || telemetryOn === undefined) {
open();
setTelemetryOn(defaultTelemetryAccepted);
}
}, [defaultTelemetryAccepted, open, setTelemetryOn, telemetryOn]);
return {
isOpen,
open: open,
close: close,
telemetryAccepted: telemetryOn === 'true',
setTelemetryAccepted: (value: boolean) => {
setTelemetryOn(value.toString());
},
};
};
export const TelemetryDialog = () => {
const { t } = useTranslation();
const { isOpen, open, close, telemetryAccepted, setTelemetryAccepted } =
useTelemetryDialog();
return (
<Dialog
title={t('ImproveVegaGovernance')}
open={isOpen}
onChange={(isOpen) => (isOpen ? open() : close())}
size="small"
>
<div className="mt-6">{t('TelemetryModalIntro')}</div>
<div className="flex items-center mt-6">
<Icon name="eye-off" className="mr-6" size={6} />
<div className="flex flex-col gap-1">
<div className="font-semibold">{t('Anonymous')}</div>
<div>{t('YourIdentityAnonymous')}</div>
</div>
</div>
<div className="flex items-center mt-6">
<Icon name="cog" className="mr-6" size={6} />
<div className="flex flex-col gap-1">
<div className="font-semibold">{t('Optional')}</div>
<div>{t('OptOutOfTelemetry')}</div>
</div>
</div>
<div className="flex items-center mt-10 gap-4">
<Button
onClick={() => {
setTelemetryAccepted(false);
close();
}}
variant="default"
data-testid="do-not-share-data-button"
>
{t('NoThanks')}
</Button>
<Button
onClick={() => {
setTelemetryAccepted(true);
close();
}}
variant="primary"
data-testid="share-data-button"
>
{telemetryAccepted ? t('ContinueSharingData') : t('ShareData')}
</Button>
</div>
</Dialog>
);
};
-4
View File
@@ -33,10 +33,6 @@ export const ContractAddresses: {
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
lockedAddress: '0x0', // TODO not deployed to this env
},
STAGNET3: {
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
lockedAddress: '0x0', // TODO not deployed to this env
},
TESTNET: {
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
lockedAddress: '0x0', // TODO not deployed to this env
@@ -1,7 +1,7 @@
import React from 'react';
export function useDocumentTitle(name?: string) {
const base = 'VEGA token';
const base = 'VEGA Governance';
React.useEffect(() => {
if (name) {
@@ -21,10 +21,10 @@ export const useGetUserBalances = (account: string | undefined) => {
token.allowance(account, config.staking_bridge_contract.address),
]);
const balance = toBigNum(b, decimals);
const walletBalance = toBigNum(w, decimals);
const lien = toBigNum(stats.lien, decimals);
const allowance = toBigNum(a, decimals);
const balance = toBigNum(b.toString(), decimals);
const walletBalance = toBigNum(w.toString(), decimals);
const lien = toBigNum(stats.lien.toString(), decimals);
const allowance = toBigNum(a.toString(), decimals);
return {
balanceFormatted: balance,
@@ -21,8 +21,14 @@ export function useRefreshAssociatedBalances() {
]);
updateBalances({
walletAssociatedBalance: toBigNum(walletAssociatedBalance, decimals),
vestingAssociatedBalance: toBigNum(vestingAssociatedBalance, decimals),
walletAssociatedBalance: toBigNum(
walletAssociatedBalance.toString(),
decimals
),
vestingAssociatedBalance: toBigNum(
vestingAssociatedBalance.toString(),
decimals
),
});
},
[staking, vesting, updateBalances, decimals]
@@ -31,12 +31,18 @@ export const useRefreshBalances = (address: string) => {
pubKey ? vesting.stake_balance(address, pubKey) : null,
]);
const balance = toBigNum(b, decimals);
const walletBalance = toBigNum(w, decimals);
const lien = toBigNum(stats.lien, decimals);
const allowance = toBigNum(a, decimals);
const walletAssociatedBalance = toBigNum(walletStakeBalance, decimals);
const vestingAssociatedBalance = toBigNum(vestingStakeBalance, decimals);
const balance = toBigNum(b.toString(), decimals);
const walletBalance = toBigNum(w.toString(), decimals);
const lien = toBigNum(stats.lien.toString(), decimals);
const allowance = toBigNum(a.toString(), decimals);
const walletAssociatedBalance = toBigNum(
walletStakeBalance ? walletStakeBalance.toString() : 0,
decimals
);
const vestingAssociatedBalance = toBigNum(
vestingStakeBalance ? vestingStakeBalance.toString() : 0,
decimals
);
updateBalances({
balanceFormatted: balance,
+29 -7
View File
@@ -66,7 +66,7 @@
"claim": "This code ({{code}}) entitles <bold>{{user}}</bold> to <bold>{{amount}} $VEGA</bold> tokens from <trancheLink>{{linkText}}</trancheLink> of the vesting contract. {{expiry}}.",
"claimExpiry": "The code expires on {{date}}",
"claimNoExpiry": "It has no expiry date",
"showRedeem": "You'll be able to redeem your unlocked tokens at token.vega.xyz/vesting",
"showRedeem": "You'll be able to redeem your unlocked tokens at governance.vega.xyz/vesting",
"codeUsed": "Code already used",
"codeUsedText": "Looks like that code has already been used. Check the Vesting page to see if you can redeem your tokens.",
"codeExpired": "Code expired",
@@ -86,7 +86,7 @@
"Awaiting action in Ethereum wallet (e.g. MetaMask)": "Awaiting action in Ethereum wallet (e.g. MetaMask)",
"Claim {amount} Vega": "Claim {{amount}} $VEGA",
"Sorry. It is not possible to claim tokens in your country or region.": "It is not possible to claim tokens in your country or region.",
"none redeemable": "Tokens in this tranche unlock on {{unlockDate}} and continue to unlock gradually until {{trancheEndDate}} when all tokens are unlocked. Come back to token.vega.xyz to redeem your tokens once they begin to unlock.",
"none redeemable": "Tokens in this tranche unlock on {{unlockDate}} and continue to unlock gradually until {{trancheEndDate}} when all tokens are unlocked. Come back to governance.vega.xyz to redeem your tokens once they begin to unlock.",
"partially redeemable": "Tokens in this tranche began to unlock on {{unlockDate}} and will continue to unlock gradually until {{trancheEndDate}} when all tokens are unlocked.",
"fully redeemable": "Tokens in this tranche have fully unlocked and can be redeemed once claimed.",
"This page can not be found, please check the URL and try again.": "This page can not be found, please check the URL and try again.",
@@ -201,6 +201,7 @@
"NewFreeform": "Freeform",
"tokenVotes": "Token votes",
"liquidityVotes": "Liquidity votes",
"castYourVote": "Cast your vote",
"yourVote": "Your vote",
"for": "For",
"against": "Against",
@@ -587,7 +588,7 @@
"tokensAgainstProposal": "Tokens against proposal",
"participationRequired": "Participation required",
"numberOfVotingParties": "Number of voting parties",
"totalTokensVotes": "Total yes tokens",
"totalTokensVotes": "Total tokens voted",
"totalTokenVotedPercentage": "Total tokens voted percentage",
"numberOfForVotes": "Number of votes for",
"numberOfAgainstVotes": "Number of votes against",
@@ -631,7 +632,10 @@
"New market": "New market",
"Market change": "Market change",
"Network parameter": "Network parameter",
"Change": "Change",
"Unknown proposal": "Unknown proposal",
"ERC20ContractAddress": "ERC20 contract address",
"MaxFaucetAmountMint": "Max faucet amount mint",
"Code": "Code",
"settled future": "settled future",
"Symbol": "Symbol",
@@ -675,8 +679,11 @@
"FilterProposalsDescription": "Filter by proposal ID or proposer ID",
"Freeform proposal": "Freeform proposal",
"NewProposal": "New proposal",
"CreateProposalAndDownloadJSONToShare": "Create proposal and download JSON to share",
"SubmitAnAgreedProposalFromTheForum": "Submit an agreed proposal from the forum",
"ProposalTypeQuestion": "What type of proposal would you like to make?",
"NetworkParameterProposal": "Update network parameter proposal",
"parameter": "parameter",
"NewMarketProposal": "New market proposal",
"UpdateMarketProposal": "Update market proposal",
"NewAssetProposal": "New asset proposal",
@@ -694,8 +701,10 @@
"UpdateMarket": "Update market",
"NewAsset": "New asset",
"UpdateAsset": "Update asset",
"AssetID": "Asset ID",
"Freeform": "Freeform",
"RawProposal": "Let me choose (raw proposal)",
"SubmitAgreedRawProposal": "Submit agreed raw proposal",
"UseMin": "Use minimum",
"UseMax": "Use maximum",
"Proposal": "Proposal",
@@ -737,6 +746,7 @@
"ProposalNotFound": "Proposal not found",
"ProposalNotFoundDetails": "The proposal you are looking for is not here, it may have been enacted before the last chain restore. You could check the Vega forums/discord instead for information about it.",
"FreeformProposal": "Freeform proposal",
"Id": "ID",
"unknownReason": "unknown reason",
"votingEnded": "Voting has ended.",
"STATUS": "STATUS",
@@ -778,9 +788,9 @@
"homeVegaTokenButtonText": "Manage tokens",
"downloadProposalJson": "Download proposal as JSON",
"networkUpgrade": "Network Upgrade",
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED": "Approved",
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING": "Pending",
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED": "Rejected",
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED": "Approved by validators",
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING": "Waiting for validator votes",
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED": "Declined by validators",
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_UNSPECIFIED": "Unspecified",
"vegaRelease{release}": "Vega Release {{release}}",
"upgradeBlockHeight": "Upgrade block height",
@@ -791,5 +801,17 @@
"67% voting power required": "67% voting power required",
"Token": "Token",
"associateVegaNow": "Associate $VEGA now",
"disconnectedNotice": "You have been disconnected. Connect your ETH wallet to the {{correctNetwork}} network to use this app."
"disconnectedNotice": "You have been disconnected. Connect your ETH wallet to the {{correctNetwork}} network to use this app.",
"connectAVegaWalletToVote": "Connect a Vega wallet with $VEGA tokens to vote on a proposal.",
"findOutMoreAboutHowToVote": "Find out more about how to vote on Vega",
"ImproveVegaGovernance": "Improve Vega governance",
"TelemetryModalIntro": "Help us identify bugs and improve Vega Governance by sharing anonymous usage data.",
"Anonymous": "Anonymous",
"YourIdentityAnonymous": "Your identity is always anonymous on Vega",
"Optional": "Optional",
"OptOutOfTelemetry": "You can opt out any time via settings",
"NoThanks": "No thanks",
"ShareData": "Share data",
"ContinueSharingData": "Continue sharing data",
"NodeUnsuitable": "Node: {{url}} is unsuitable"
}
+1 -1
View File
@@ -24,7 +24,7 @@
type="font/woff2"
crossorigin="anonymous"
/>
<title>Vega Token dApp</title>
<title>Vega Governance dApp</title>
<script src="./assets/env-config.js"></script>
</head>
<body class="h-full">
@@ -50,7 +50,22 @@ export const useTranches = create<TranchesStore>()((set) => ({
?.map((t) => {
const tranche_progress =
t.duration !== 0 ? (now - t.cliff_start) / t.duration : 0;
const lockedDecimal = tranche_progress < 0 ? 1 : 1 - tranche_progress;
let lockedDecimal;
if (t.duration !== 0) {
if (tranche_progress < 0) {
lockedDecimal = 1;
} else {
lockedDecimal = 1 - tranche_progress;
}
} else {
if (now < t.cliff_start) {
lockedDecimal = 1;
} else {
lockedDecimal = 0;
}
}
const clampedLockedDecimal = Math.max(0, Math.min(1, lockedDecimal));
return {
tranche_id: t.tranche_id,
tranche_start: secondsToDate(t.cliff_start),
@@ -60,7 +75,7 @@ export const useTranches = create<TranchesStore>()((set) => ({
toBigNum(t.current_balance, decimals)
),
locked_amount: toBigNum(t.initial_balance, decimals).times(
lockedDecimal
clampedLockedDecimal
),
users: t.users,
};
+3 -3
View File
@@ -15,7 +15,6 @@ import Routes from '../routes';
import { ExternalLinks, removePaginationWrapper } from '@vegaprotocol/utils';
import { useNodesQuery } from '../staking/home/__generated__/Nodes';
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
import { useProtocolUpgradesQuery } from '../proposals/protocol-upgrade/__generated__/ProtocolUpgradeProposals';
import {
getNotRejectedProposals,
getNotRejectedProtocolUpgradeProposals,
@@ -25,7 +24,8 @@ import * as Schema from '@vegaprotocol/types';
import type { RouteChildProps } from '..';
import type { ProposalFieldsFragment } from '../proposals/proposals/__generated__/Proposals';
import type { NodesFragmentFragment } from '../staking/home/__generated__/Nodes';
import type { ProtocolUpgradeProposalFieldsFragment } from '../proposals/protocol-upgrade/__generated__/ProtocolUpgradeProposals';
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
import { useProtocolUpgradeProposalsQuery } from '@vegaprotocol/proposals';
const nodesToShow = 6;
@@ -181,7 +181,7 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
data: protocolUpgradesData,
loading: protocolUpgradesLoading,
error: protocolUpgradesError,
} = useProtocolUpgradesQuery({
} = useProtocolUpgradeProposalsQuery({
pollInterval: 5000,
fetchPolicy: 'network-only',
errorPolicy: 'ignore',
@@ -1,7 +1,11 @@
import { useTranslation } from 'react-i18next';
import * as Schema from '@vegaprotocol/types';
import { Icon } from '@vegaprotocol/ui-toolkit';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import { ProposalState } from '@vegaprotocol/types';
import { ProposalInfoLabel } from '../proposal-info-label';
import type { ReactNode } from 'react';
import type { ProposalInfoLabelVariant } from '../proposal-info-label';
export const CurrentProposalState = ({
proposal,
@@ -9,19 +13,63 @@ export const CurrentProposalState = ({
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
}) => {
const { t } = useTranslation();
let className = 'text-white';
let proposalStatus: ReactNode;
let variant = 'tertiary' as ProposalInfoLabelVariant;
if (
proposal?.state === Schema.ProposalState.STATE_DECLINED ||
proposal?.state === Schema.ProposalState.STATE_FAILED ||
proposal?.state === Schema.ProposalState.STATE_REJECTED
) {
className = 'text-danger';
} else if (
proposal?.state === Schema.ProposalState.STATE_ENACTED ||
proposal?.state === Schema.ProposalState.STATE_PASSED
) {
className = 'text-white';
switch (proposal?.state) {
case ProposalState.STATE_ENACTED: {
proposalStatus = (
<>
<span className="mr-2">{t('voteState_Enacted')}</span>
<Icon name={'tick'} />
</>
);
break;
}
case ProposalState.STATE_PASSED: {
proposalStatus = (
<>
<span className="mr-2">{t('voteState_Passed')}</span>
<Icon name={'tick'} />
</>
);
break;
}
case ProposalState.STATE_WAITING_FOR_NODE_VOTE: {
proposalStatus = (
<>
<span className="mr-2">{t('voteState_WaitingForNodeVote')}</span>
<Icon name={'time'} />
</>
);
break;
}
case ProposalState.STATE_OPEN: {
variant = 'primary' as ProposalInfoLabelVariant;
proposalStatus = <>{t('voteState_Open')}</>;
break;
}
case ProposalState.STATE_DECLINED: {
proposalStatus = (
<>
<span className="mr-2">{t('voteState_Declined')}</span>
<Icon name={'cross'} />
</>
);
break;
}
case ProposalState.STATE_REJECTED: {
proposalStatus = (
<>
<span className="mr-2">{t('voteState_Rejected')}</span>
<Icon name={'warning-sign'} />
</>
);
break;
}
}
return <span className={className}>{t(`${proposal?.state}`)}</span>;
return (
<ProposalInfoLabel variant={variant}>{proposalStatus}</ProposalInfoLabel>
);
};
@@ -2,8 +2,8 @@ import type { MockedResponse } from '@apollo/client/testing';
import { MockedProvider } from '@apollo/client/testing';
import { render, screen } from '@testing-library/react';
import { ProposalRejectionReason, ProposalState } from '@vegaprotocol/types';
import type { NetworkParamsQuery } from '@vegaprotocol/react-helpers';
import { NetworkParamsDocument } from '@vegaprotocol/react-helpers';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { generateProposal } from '../../test-helpers/generate-proposals';
import { CurrentProposalStatus } from './current-proposal-status';
@@ -16,17 +16,12 @@ it('Renders all data for table', () => {
render(<ProposalChangeTable proposal={proposal} />);
expect(screen.getByText('ID')).toBeInTheDocument();
expect(screen.getByText(proposal?.id as string)).toBeInTheDocument();
expect(screen.getByText('State')).toBeInTheDocument();
expect(screen.getByText('Open')).toBeInTheDocument();
expect(screen.getByText('Closes on')).toBeInTheDocument();
expect(
screen.getByText(
formatDateWithLocalTimezone(new Date(proposal?.terms.closingDatetime))
)
).toBeInTheDocument();
expect(screen.getByText('Proposed enactment')).toBeInTheDocument();
expect(
screen.getByText(
@@ -35,17 +30,12 @@ it('Renders all data for table', () => {
)
)
).toBeInTheDocument();
expect(screen.getByText('Proposed by')).toBeInTheDocument();
expect(screen.getByText(proposal?.party.id ?? '')).toBeInTheDocument();
expect(screen.getByText('Proposed on')).toBeInTheDocument();
expect(
screen.getByText(formatDateWithLocalTimezone(new Date(proposal?.datetime)))
).toBeInTheDocument();
expect(screen.getByText('Type')).toBeInTheDocument();
expect(screen.getByText('Network parameter')).toBeInTheDocument();
});
it('Changes data based on if data is in future or past', () => {
@@ -53,17 +43,12 @@ it('Changes data based on if data is in future or past', () => {
state: ProposalState.STATE_ENACTED,
});
render(<ProposalChangeTable proposal={proposal} />);
expect(screen.getByText('State')).toBeInTheDocument();
expect(screen.getByText('Enacted')).toBeInTheDocument();
expect(screen.getByText('Closed on')).toBeInTheDocument();
expect(
screen.getByText(
formatDateWithLocalTimezone(new Date(proposal?.terms.closingDatetime))
)
).toBeInTheDocument();
expect(screen.getByText('Enacted on')).toBeInTheDocument();
expect(
screen.getByText(
@@ -104,7 +89,6 @@ it('Renders error details and rejection reason if present', () => {
render(<ProposalChangeTable proposal={proposal} />);
expect(screen.getByText('Error details')).toBeInTheDocument();
expect(screen.getByText(errorDetails)).toBeInTheDocument();
expect(screen.getByText('Rejection reason')).toBeInTheDocument();
expect(
screen.getByText(ProposalRejectionReason.PROPOSAL_ERROR_CLOSE_TIME_TOO_LATE)
@@ -6,7 +6,6 @@ import {
KeyValueTableRow,
RoundedWrapper,
} from '@vegaprotocol/ui-toolkit';
import { CurrentProposalState } from '../current-proposal-state';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
@@ -20,16 +19,12 @@ export const ProposalChangeTable = ({ proposal }: ProposalChangeTableProps) => {
const terms = proposal?.terms;
return (
<RoundedWrapper>
<RoundedWrapper paddingBottom={true}>
<KeyValueTable data-testid="proposal-change-table">
<KeyValueTableRow>
{t('id')}
{proposal?.id}
</KeyValueTableRow>
<KeyValueTableRow>
{t('state')}
<CurrentProposalState proposal={proposal} />
</KeyValueTableRow>
<KeyValueTableRow>
{isFuture(new Date(terms?.closingDatetime))
? t('closesOn')
@@ -50,26 +45,24 @@ export const ProposalChangeTable = ({ proposal }: ProposalChangeTableProps) => {
{t('proposedBy')}
<span style={{ wordBreak: 'break-word' }}>{proposal?.party.id}</span>
</KeyValueTableRow>
<KeyValueTableRow>
<KeyValueTableRow
noBorder={!proposal?.rejectionReason && !proposal?.errorDetails}
>
{t('proposedOn')}
{formatDateWithLocalTimezone(new Date(proposal?.datetime))}
</KeyValueTableRow>
{proposal?.rejectionReason ? (
<KeyValueTableRow>
<KeyValueTableRow noBorder={!proposal?.errorDetails}>
{t('rejectionReason')}
{proposal.rejectionReason}
</KeyValueTableRow>
) : null}
{proposal?.errorDetails ? (
<KeyValueTableRow>
<KeyValueTableRow noBorder={true}>
{t('errorDetails')}
{proposal.errorDetails}
</KeyValueTableRow>
) : null}
<KeyValueTableRow>
{t('type')}
{t(`${proposal?.terms.change.__typename}`)}
</KeyValueTableRow>
</KeyValueTable>
</RoundedWrapper>
);
@@ -1,68 +1,68 @@
import { render, screen } from '@testing-library/react';
import { generateProposal } from '../../test-helpers/generate-proposals';
import {
generateNoVotes,
generateProposal,
generateYesVotes,
} from '../../test-helpers/generate-proposals';
import { ProposalHeader } from './proposal-header';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import { ProposalRejectionReason, ProposalState } from '@vegaprotocol/types';
import { lastWeek, nextWeek } from '../../test-helpers/mocks';
const renderComponent = (proposal: ProposalQuery['proposal']) => (
<ProposalHeader proposal={proposal} />
);
const renderComponent = (
proposal: ProposalQuery['proposal'],
isListItem = true
) => render(<ProposalHeader proposal={proposal} isListItem={isListItem} />);
describe('Proposal header', () => {
it('Renders New market proposal', () => {
render(
renderComponent(
generateProposal({
rationale: {
title: 'New some market',
description: 'A new some market',
},
terms: {
change: {
__typename: 'NewMarket',
instrument: {
__typename: 'InstrumentConfiguration',
name: 'Some market',
code: 'FX:BTCUSD/DEC99',
futureProduct: {
__typename: 'FutureProduct',
settlementAsset: {
__typename: 'Asset',
symbol: 'tGBP',
},
renderComponent(
generateProposal({
rationale: {
title: 'New some market',
description: 'A new some market',
},
terms: {
change: {
__typename: 'NewMarket',
instrument: {
__typename: 'InstrumentConfiguration',
name: 'Some market',
code: 'FX:BTCUSD/DEC99',
futureProduct: {
__typename: 'FutureProduct',
settlementAsset: {
__typename: 'Asset',
symbol: 'tGBP',
},
},
},
},
})
)
},
})
);
expect(screen.getByTestId('proposal-title')).toHaveTextContent(
'New some market'
);
expect(screen.getByTestId('proposal-type')).toHaveTextContent('New market');
expect(screen.getByTestId('proposal-description')).toHaveTextContent(
'A new some market'
);
expect(screen.getByTestId('proposal-details')).toHaveTextContent(
'tGBP settled future.'
);
});
it('Renders Update market proposal', () => {
render(
renderComponent(
generateProposal({
rationale: {
title: 'New market id',
renderComponent(
generateProposal({
rationale: {
title: 'New market id',
},
terms: {
change: {
__typename: 'UpdateMarket',
marketId: 'MarketId',
},
terms: {
change: {
__typename: 'UpdateMarket',
marketId: 'MarketId',
},
},
})
)
},
})
);
expect(screen.getByTestId('proposal-title')).toHaveTextContent(
'New market id'
@@ -79,53 +79,49 @@ describe('Proposal header', () => {
});
it('Renders New asset proposal - ERC20', () => {
render(
renderComponent(
generateProposal({
rationale: {
title: 'New asset: Fake currency',
description: '',
},
terms: {
change: {
__typename: 'NewAsset',
name: 'Fake currency',
symbol: 'FAKE',
source: {
__typename: 'ERC20',
contractAddress: '0x0',
},
renderComponent(
generateProposal({
rationale: {
title: 'New asset: Fake currency',
description: '',
},
terms: {
change: {
__typename: 'NewAsset',
name: 'Fake currency',
symbol: 'FAKE',
source: {
__typename: 'ERC20',
contractAddress: '0x0',
},
},
})
)
},
})
);
expect(screen.getByTestId('proposal-title')).toHaveTextContent(
'New asset: Fake currency'
);
expect(screen.getByTestId('proposal-type')).toHaveTextContent('New asset');
expect(screen.getByTestId('proposal-details')).toHaveTextContent(
'Symbol: FAKE. ERC20 0x0'
'Symbol: FAKE. ERC20 contract address: 0x0'
);
});
it('Renders New asset proposal - BuiltInAsset', () => {
render(
renderComponent(
generateProposal({
terms: {
change: {
__typename: 'NewAsset',
name: 'Fake currency',
symbol: 'BIA',
source: {
__typename: 'BuiltinAsset',
maxFaucetAmountMint: '300',
},
renderComponent(
generateProposal({
terms: {
change: {
__typename: 'NewAsset',
name: 'Fake currency',
symbol: 'BIA',
source: {
__typename: 'BuiltinAsset',
maxFaucetAmountMint: '300',
},
},
})
)
},
})
);
expect(screen.getByTestId('proposal-title')).toHaveTextContent(
'Unknown proposal'
@@ -137,24 +133,22 @@ describe('Proposal header', () => {
});
it('Renders Update network', () => {
render(
renderComponent(
generateProposal({
rationale: {
title: 'Network parameter',
},
terms: {
change: {
__typename: 'UpdateNetworkParameter',
networkParameter: {
__typename: 'NetworkParameter',
key: 'Network key',
value: 'Network value',
},
renderComponent(
generateProposal({
rationale: {
title: 'Network parameter',
},
terms: {
change: {
__typename: 'UpdateNetworkParameter',
networkParameter: {
__typename: 'NetworkParameter',
key: 'Network key',
value: 'Network value',
},
},
})
)
},
})
);
expect(screen.getByTestId('proposal-title')).toHaveTextContent(
'Network parameter'
@@ -167,122 +161,211 @@ describe('Proposal header', () => {
);
});
it('Renders Freeform network - short rationale', () => {
render(
renderComponent(
generateProposal({
id: 'short',
rationale: {
title: '0x0',
it('Renders Freeform proposal - short rationale', () => {
renderComponent(
generateProposal({
id: 'short',
rationale: {
title: '0x0',
},
terms: {
change: {
__typename: 'NewFreeform',
},
terms: {
change: {
__typename: 'NewFreeform',
},
},
})
)
},
})
);
expect(screen.getByTestId('proposal-title')).toHaveTextContent('0x0');
expect(screen.getByTestId('proposal-type')).toHaveTextContent('Freeform');
expect(
screen.queryByTestId('proposal-description')
).not.toBeInTheDocument();
expect(screen.getByTestId('proposal-details')).toHaveTextContent('short');
});
it('Renders Freeform proposal - long rationale (105 chars)', () => {
render(
renderComponent(
generateProposal({
id: 'long',
rationale: {
title: '0x0',
description:
'Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean dolor.',
it('Renders Freeform proposal - long rationale (105 chars) - listing', () => {
renderComponent(
generateProposal({
id: 'long',
rationale: {
title: '0x0',
description:
'Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean dolor.',
},
terms: {
change: {
__typename: 'NewFreeform',
},
terms: {
change: {
__typename: 'NewFreeform',
},
},
})
)
},
})
);
// For a rationale over 100 chars, we expect the header to be truncated at
// 100 chars with ellipsis and the details-one element to contain the rest.
expect(screen.getByTestId('proposal-title')).toHaveTextContent('0x0');
expect(screen.getByTestId('proposal-type')).toHaveTextContent('Freeform');
// Rationale in list view is not rendered
expect(
screen.queryByTestId('proposal-description')
).not.toBeInTheDocument();
});
it('Renders Freeform proposal - long rationale (105 chars) - details', () => {
renderComponent(
generateProposal({
id: 'long',
rationale: {
title: '0x0',
description:
'Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean dolor.',
},
terms: {
change: {
__typename: 'NewFreeform',
},
},
}),
false
);
expect(screen.getByTestId('proposal-description')).toHaveTextContent(
'Class aptent taciti sociosqu ad litora torquent per conubia'
/Class aptent/
);
expect(screen.getByTestId('proposal-details')).toHaveTextContent('long');
});
// Remove once proposals have rationale and re-enable above tests
it('Renders Freeform proposal - id for title', () => {
render(
renderComponent(
generateProposal({
id: 'freeform id',
rationale: {
title: 'freeform',
renderComponent(
generateProposal({
id: 'freeform id',
rationale: {
title: 'freeform',
},
terms: {
change: {
__typename: 'NewFreeform',
},
terms: {
change: {
__typename: 'NewFreeform',
},
},
})
)
},
})
);
expect(screen.getByTestId('proposal-title')).toHaveTextContent('freeform');
expect(screen.getByTestId('proposal-type')).toHaveTextContent('Freeform');
expect(
screen.queryByTestId('proposal-description')
).not.toBeInTheDocument();
expect(screen.queryByTestId('proposal-details')).toHaveTextContent(
'freeform id'
);
});
it('Renders asset change proposal header', () => {
render(
renderComponent(
generateProposal({
terms: {
change: {
__typename: 'UpdateAsset',
assetId: 'foo',
},
renderComponent(
generateProposal({
terms: {
change: {
__typename: 'UpdateAsset',
assetId: 'foo',
},
})
)
},
})
);
expect(screen.getByTestId('proposal-type')).toHaveTextContent(
'Update asset'
);
expect(screen.getByTestId('proposal-details')).toHaveTextContent(
'Update asset'
);
expect(screen.getByText('foo')).toBeInTheDocument();
});
it("Renders unknown proposal if it's a different proposal type", () => {
render(
renderComponent(
generateProposal({
terms: {
change: {
// @ts-ignore unknown proposal
__typename: 'Foo',
},
renderComponent(
generateProposal({
terms: {
change: {
// @ts-ignore unknown proposal
__typename: 'Foo',
},
})
)
},
})
);
expect(screen.getByTestId('proposal-title')).toHaveTextContent(
'Unknown proposal'
);
});
it('Renders proposal state: Enacted', () => {
renderComponent(
generateProposal({
state: ProposalState.STATE_ENACTED,
terms: {
enactmentDatetime: lastWeek.toString(),
},
})
);
expect(screen.getByTestId('proposal-status')).toHaveTextContent('Enacted');
});
it('Renders proposal state: Passed', () => {
renderComponent(
generateProposal({
state: ProposalState.STATE_PASSED,
terms: {
closingDatetime: lastWeek.toString(),
enactmentDatetime: nextWeek.toString(),
},
})
);
expect(screen.getByTestId('proposal-status')).toHaveTextContent('Passed');
});
it('Renders proposal state: Waiting for node vote', () => {
renderComponent(
generateProposal({
state: ProposalState.STATE_WAITING_FOR_NODE_VOTE,
terms: {
enactmentDatetime: nextWeek.toString(),
},
})
);
expect(screen.getByTestId('proposal-status')).toHaveTextContent(
'Waiting for node vote'
);
});
it('Renders proposal state: Open', () => {
renderComponent(
generateProposal({
state: ProposalState.STATE_OPEN,
votes: {
__typename: 'ProposalVotes',
yes: generateYesVotes(3000, 1000000000000000000),
no: generateNoVotes(0),
},
terms: {
closingDatetime: nextWeek.toString(),
},
})
);
expect(screen.getByTestId('proposal-status')).toHaveTextContent('Open');
});
it('Renders proposal state: Declined - majority not reached', () => {
renderComponent(
generateProposal({
state: ProposalState.STATE_DECLINED,
terms: {
enactmentDatetime: lastWeek.toString(),
},
votes: {
no: generateNoVotes(1, 1000000000000000000),
yes: generateYesVotes(1, 1000000000000000000),
},
})
);
expect(screen.getByTestId('proposal-status')).toHaveTextContent('Declined');
});
it('Renders proposal state: Rejected', () => {
renderComponent(
generateProposal({
state: ProposalState.STATE_REJECTED,
terms: {
enactmentDatetime: lastWeek.toString(),
},
rejectionReason:
ProposalRejectionReason.PROPOSAL_ERROR_INVALID_FUTURE_PRODUCT,
})
);
expect(screen.getByTestId('proposal-status')).toHaveTextContent('Rejected');
});
});
@@ -1,23 +1,27 @@
import { useTranslation } from 'react-i18next';
import { Intent, Lozenge } from '@vegaprotocol/ui-toolkit';
import { Lozenge } from '@vegaprotocol/ui-toolkit';
import { shorten } from '@vegaprotocol/utils';
import { Heading, SubHeading } from '../../../../components/heading';
import type { ReactNode } from 'react';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import ReactMarkdown from 'react-markdown';
import { truncateMiddle } from '../../../../lib/truncate-middle';
import { CurrentProposalState } from '../current-proposal-state';
import { ProposalInfoLabel } from '../proposal-info-label';
export const ProposalHeader = ({
proposal,
useSubHeading = true,
isListItem = true,
}: {
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
useSubHeading?: boolean;
isListItem?: boolean;
}) => {
const { t } = useTranslation();
const change = proposal?.terms.change;
let details: ReactNode;
let proposalType: ReactNode;
let proposalType = '';
let title = proposal?.rationale.title.trim();
let description = proposal?.rationale.description.trim();
@@ -30,10 +34,12 @@ export const ProposalHeader = ({
switch (change?.__typename) {
case 'NewMarket': {
proposalType = t('NewMarket');
proposalType = 'NewMarket';
details = (
<>
{t('Code')}: {change.instrument.code}.{' '}
<span>
{t('Code')}: {change.instrument.code}.
</span>{' '}
{change.instrument.futureProduct?.settlementAsset.symbol ? (
<>
<span className="font-semibold">
@@ -49,54 +55,61 @@ export const ProposalHeader = ({
break;
}
case 'UpdateMarket': {
proposalType = t('UpdateMarket');
details = `${t('Market change')}: ${change.marketId}`;
proposalType = 'UpdateMarket';
details = (
<>
<span>{t('Market change')}:</span>{' '}
<span>{truncateMiddle(change.marketId)}</span>
</>
);
break;
}
case 'NewAsset': {
proposalType = t('NewAsset');
proposalType = 'NewAsset';
details = (
<>
{t('Symbol')}: {change.symbol}.{' '}
<Lozenge>
{change.source.__typename === 'ERC20' &&
`ERC20 ${change.source.contractAddress}`}
{change.source.__typename === 'BuiltinAsset' &&
`${t('Max faucet amount mint')}: ${
change.source.maxFaucetAmountMint
}`}
</Lozenge>
<span>{t('Symbol')}:</span> <Lozenge>{change.symbol}.</Lozenge>{' '}
{change.source.__typename === 'ERC20' && (
<>
<span>{t('ERC20ContractAddress')}:</span>{' '}
<Lozenge>{change.source.contractAddress}</Lozenge>
</>
)}{' '}
{change.source.__typename === 'BuiltinAsset' && (
<>
<span>{t('MaxFaucetAmountMint')}:</span>{' '}
<Lozenge>{change.source.maxFaucetAmountMint}</Lozenge>
</>
)}
</>
);
break;
}
case 'UpdateNetworkParameter': {
proposalType = t('NetworkParameter');
const parametersClasses = 'font-mono leading-none';
proposalType = 'NetworkParameter';
details = (
<>
<span className={`${parametersClasses} mr-2`}>
{change.networkParameter.key}
</span>{' '}
{t('to')}{' '}
<span className={`${parametersClasses} ml-2`}>
{change.networkParameter.value}
<span>{t('Change')}:</span>{' '}
<Lozenge>{change.networkParameter.key}</Lozenge>{' '}
<span>{t('to')}</span>{' '}
<span className="whitespace-nowrap">
<Lozenge>{change.networkParameter.value}</Lozenge>
</span>
</>
);
break;
}
case 'NewFreeform': {
proposalType = t('Freeform');
details = `${t('FreeformProposal')}: ${proposal?.id}`;
proposalType = 'Freeform';
details = <span />;
break;
}
case 'UpdateAsset': {
proposalType = t('UpdateAsset');
proposalType = 'UpdateAsset';
details = (
<>
`${t('Update asset')}`;
<Lozenge>{change.assetId}</Lozenge>
<span>{t('AssetID')}:</span>{' '}
<Lozenge>{truncateMiddle(change.assetId)}</Lozenge>
</>
);
break;
@@ -104,9 +117,9 @@ export const ProposalHeader = ({
}
return (
<div className="text-sm mb-2">
<>
<div data-testid="proposal-title">
{useSubHeading ? (
{isListItem ? (
<header>
<SubHeading title={titleContent || t('Unknown proposal')} />
</header>
@@ -116,18 +129,39 @@ export const ProposalHeader = ({
</div>
<div className="flex items-center gap-2 mb-4">
{proposalType && (
<div data-testid="proposal-type">
<Lozenge variant={Intent.None}>{proposalType}</Lozenge>
</div>
)}
<div data-testid="proposal-type">
<ProposalInfoLabel variant="secondary">
{t(`${proposalType}`)}
</ProposalInfoLabel>
</div>
{description && (
<div data-testid="proposal-description">{description}</div>
)}
<div data-testid="proposal-status">
<CurrentProposalState proposal={proposal} />
</div>
</div>
{details && <div data-testid="proposal-details">{details}</div>}
</div>
{details && (
<div data-testid="proposal-details" className="break-words my-10">
{details}
</div>
)}
{description && !isListItem && (
<div data-testid="proposal-description">
{/*<div className="uppercase mr-2">{t('ProposalDescription')}:</div>*/}
<SubHeading title={t('ProposalDescription')} />
<ReactMarkdown
className="react-markdown-container"
/* Prevents HTML embedded in the description from rendering */
skipHtml={true}
/* Stops users embedding images which could be used for tracking */
disallowedElements={['img']}
linkTarget="_blank"
>
{description}
</ReactMarkdown>
</div>
)}
</>
);
};
@@ -0,0 +1 @@
export * from './proposal-info-label';
@@ -0,0 +1,35 @@
import classNames from 'classnames';
import type { ReactNode } from 'react';
export type ProposalInfoLabelVariant =
| 'primary'
| 'secondary'
| 'tertiary'
| 'highlight';
const base = 'rounded-md px-2 py-1 font-alpha';
const primary = 'bg-vega-light-150 text-black';
const secondary = 'bg-vega-dark-200 text-white';
const tertiary = 'bg-vega-dark-150 text-white';
const highlight = 'bg-vega-yellow text-black';
const getClassname = (variant: ProposalInfoLabelVariant) => {
return classNames(base, {
[primary]: variant === 'primary',
[secondary]: variant === 'secondary',
[tertiary]: variant === 'tertiary',
[highlight]: variant === 'highlight',
});
};
interface ProposalInfoLabelProps {
children: ReactNode;
variant?: ProposalInfoLabelVariant;
}
export const ProposalInfoLabel = ({
children,
variant = 'primary',
}: ProposalInfoLabelProps) => {
return <div className={getClassname(variant)}>{children}</div>;
};
@@ -1,8 +1,10 @@
import { useTranslation } from 'react-i18next';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { Icon, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
import type { PartialDeep } from 'type-fest';
import type * as Schema from '@vegaprotocol/types';
import { useState } from 'react';
import classnames from 'classnames';
export const ProposalTermsJson = ({
terms,
@@ -10,10 +12,26 @@ export const ProposalTermsJson = ({
terms: PartialDeep<Schema.ProposalTerms>;
}) => {
const { t } = useTranslation();
const [showDetails, setShowDetails] = useState(false);
const showDetailsIconClasses = classnames('mb-4', {
'rotate-180': showDetails,
});
return (
<section>
<SubHeading title={t('proposalTerms')} />
<SyntaxHighlighter data={terms} />
<button
onClick={() => setShowDetails(!showDetails)}
data-testid="proposal-terms-toggle"
>
<div className="flex items-center gap-3">
<SubHeading title={t('proposalTerms')} />
<div className={showDetailsIconClasses}>
<Icon name="chevron-down" size={8} />
</div>
</div>
</button>
{showDetails && <SyntaxHighlighter data={terms} />}
</section>
);
};
@@ -1,4 +1,4 @@
import { render, screen } from '@testing-library/react';
import { render, screen, fireEvent } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { ProposalVotesTable } from './proposal-votes-table';
@@ -46,6 +46,7 @@ describe('Proposal Votes Table', () => {
it('should show vote breakdown fields, excluding custom update market fields', () => {
renderComponent();
fireEvent.click(screen.getByTestId('vote-breakdown-toggle'));
expect(screen.getByText('Expected to pass')).toBeInTheDocument();
expect(screen.getByText('Token majority met')).toBeInTheDocument();
expect(screen.getByText('Token participation met')).toBeInTheDocument();
@@ -55,7 +56,7 @@ describe('Proposal Votes Table', () => {
expect(screen.getByText('Participation required')).toBeInTheDocument();
expect(screen.getByText('Majority Required')).toBeInTheDocument();
expect(screen.getByText('Number of voting parties')).toBeInTheDocument();
expect(screen.getByText('Total yes tokens')).toBeInTheDocument();
expect(screen.getByText('Total tokens voted')).toBeInTheDocument();
expect(
screen.getByText('Total tokens voted percentage')
).toBeInTheDocument();
@@ -70,13 +71,14 @@ describe('Proposal Votes Table', () => {
it('displays different breakdown fields for update market proposal', () => {
renderComponent(updateMarketProposal, updateMarketProposalType);
fireEvent.click(screen.getByTestId('vote-breakdown-toggle'));
expect(screen.getByText('Liquidity majority met')).toBeInTheDocument();
expect(screen.getByText('Liquidity participation met')).toBeInTheDocument();
expect(
screen.getByText('Liquidity shares for proposal')
).toBeInTheDocument();
expect(screen.queryByText('Number of voting parties')).toBeNull();
expect(screen.queryByText('Total yes tokens')).toBeNull();
expect(screen.queryByText('Total tokens voted')).toBeNull();
expect(screen.queryByText('Total tokens voted percentage')).toBeNull();
expect(screen.queryByText('Number of votes for')).toBeNull();
expect(screen.queryByText('Number of votes against')).toBeNull();
@@ -86,6 +88,7 @@ describe('Proposal Votes Table', () => {
it('displays if an update market proposal will pass by token vote', () => {
renderComponent(updateMarketProposal, updateMarketProposalType);
fireEvent.click(screen.getByTestId('vote-breakdown-toggle'));
expect(screen.getByText('👍 by token vote')).toBeInTheDocument();
});
@@ -110,6 +113,7 @@ describe('Proposal Votes Table', () => {
}),
updateMarketProposalType
);
fireEvent.click(screen.getByTestId('vote-breakdown-toggle'));
expect(screen.getByText('👍 by liquidity vote')).toBeInTheDocument();
});
});

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