Compare commits
149
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d959e37e59 | ||
|
|
64db83fe52 | ||
|
|
ac4762f9d7 | ||
|
|
1195309b61 | ||
|
|
8ce77e23ba | ||
|
|
5cae2ce400 | ||
|
|
b8c9f9772e | ||
|
|
c3e39b6e15 | ||
|
|
77a391448b | ||
|
|
484d7888cf | ||
|
|
187f1929fe | ||
|
|
0a4333645b | ||
|
|
310506e5af | ||
|
|
0b33ed4299 | ||
|
|
13f2e51798 | ||
|
|
fc047feeee | ||
|
|
005455c870 | ||
|
|
2c2bc391e8 | ||
|
|
445a085190 | ||
|
|
bb1b236cdf | ||
|
|
da66b7b20d | ||
|
|
ec12811f72 | ||
|
|
180de8cf25 | ||
|
|
df88e77cdf | ||
|
|
9441aee8cf | ||
|
|
2353812834 | ||
|
|
bba2b3c177 | ||
|
|
ae57bd92f4 | ||
|
|
115b642140 | ||
|
|
ce3da97a8a | ||
|
|
cabd99d3ef | ||
|
|
597e07608f | ||
|
|
e451dc54b3 | ||
|
|
9703c3b7a6 | ||
|
|
c22b6f3ce9 | ||
|
|
c740c11eaa | ||
|
|
d1fabb31a3 | ||
|
|
94f045a60b | ||
|
|
1af375bab8 | ||
|
|
5a48ba4a33 | ||
|
|
d1fd9184ce | ||
|
|
8f29824f9e | ||
|
|
fc3c73ad24 | ||
|
|
1027827576 | ||
|
|
0089920d4c | ||
|
|
35896a9cf5 | ||
|
|
5a90ebe12e | ||
|
|
6be117086a | ||
|
|
9c6dd9f254 | ||
|
|
a675576a52 | ||
|
|
98d248e02e | ||
|
|
c8d55c6293 | ||
|
|
3467feb3e5 | ||
|
|
bdf1663709 | ||
|
|
d775573543 | ||
|
|
c0fdc8d570 | ||
|
|
a9ebb36b9b | ||
|
|
f6c0082f2d | ||
|
|
931ad75cc9 | ||
|
|
f25a58a3c3 | ||
|
|
37340b4dc3 | ||
|
|
17ba3eb351 | ||
|
|
8f966a4ba6 | ||
|
|
cc7f403718 | ||
|
|
9184c2374c | ||
|
|
37247a504a | ||
|
|
2e7a6a6458 | ||
|
|
bf6c13f523 | ||
|
|
a6f3a08d2f | ||
|
|
f13e456a29 | ||
|
|
5cab040189 | ||
|
|
e47b868c53 | ||
|
|
b6286cd0f3 | ||
|
|
f66e976b66 | ||
|
|
866e7232db | ||
|
|
5a8ff90890 | ||
|
|
7b8f654906 | ||
|
|
d6f39049bd | ||
|
|
1d06be8f4e | ||
|
|
5eba8fe28f | ||
|
|
2ba0e9a1b2 | ||
|
|
43d3754c64 | ||
|
|
aae5c44fa4 | ||
|
|
878bed9c7a | ||
|
|
6f9f432c90 | ||
|
|
3f01b93159 | ||
|
|
473c244d7b | ||
|
|
d6a32f5090 | ||
|
|
71540a90fb | ||
|
|
cefdbe6a3c | ||
|
|
3928dd5c0e | ||
|
|
1521bab4c4 | ||
|
|
b3036d520f | ||
|
|
429a5a23d3 | ||
|
|
5b02fd5d54 | ||
|
|
b8309a76e7 | ||
|
|
e8ae085c06 | ||
|
|
fdcd24847c | ||
|
|
e054db39b5 | ||
|
|
a01e48d508 | ||
|
|
0d96c487d9 | ||
|
|
011e4e4cec | ||
|
|
d6e2432955 | ||
|
|
18c034b910 | ||
|
|
849cbb43c4 | ||
|
|
cd34cb181f | ||
|
|
97b3f4decf | ||
|
|
0465fb8ca9 | ||
|
|
22af89e78c | ||
|
|
adfd2f41b6 | ||
|
|
d9b1aa6da3 | ||
|
|
205f369cdc | ||
|
|
9f63fde123 | ||
|
|
f2c70e6da4 | ||
|
|
e8ff1b0b60 | ||
|
|
f5989b0022 | ||
|
|
653ca034f2 | ||
|
|
ef25552311 | ||
|
|
0a8439d125 | ||
|
|
702ea0c6b4 | ||
|
|
0f2b86770a | ||
|
|
cd6d350047 | ||
|
|
c5a06c57ac | ||
|
|
5bb31fa38d | ||
|
|
fd8f38803c | ||
|
|
a22f8f0ef1 | ||
|
|
c2d5c71f35 | ||
|
|
f88c35648e | ||
|
|
348c61530e | ||
|
|
f364dabe2f | ||
|
|
1ae1fdff5e | ||
|
|
3ed615c36e | ||
|
|
6b50816234 | ||
|
|
f5e67a0c2d | ||
|
|
e4d4646878 | ||
|
|
bbd1536c18 | ||
|
|
f8444c0c88 | ||
|
|
b1adf776c0 | ||
|
|
ad898ab0e8 | ||
|
|
5b0fffc5cb | ||
|
|
a9dbc0f6eb | ||
|
|
a71786817f | ||
|
|
9ee0cb7b65 | ||
|
|
8c4aa41240 | ||
|
|
91ac977704 | ||
|
|
1190033776 | ||
|
|
b99e2235b4 | ||
|
|
002bc4f188 | ||
|
|
0c2af8c75f |
@@ -14,8 +14,7 @@ What we need to achieve and who for
|
|||||||
|
|
||||||
## Tasks
|
## Tasks
|
||||||
|
|
||||||
- [ ] What do we need to do first
|
- [ ]
|
||||||
- [ ] and then what?
|
- [ ]
|
||||||
- [ ] Etc.
|
|
||||||
|
|
||||||
## Additional details / background info
|
## Additional details / background info
|
||||||
|
|||||||
@@ -22,11 +22,14 @@ So that
|
|||||||
|
|
||||||
## Tasks
|
## Tasks
|
||||||
|
|
||||||
- [ ] Explore and sketch
|
- [ ] UX (if needed)
|
||||||
|
- [ ] Design (if needed)
|
||||||
- [ ] Team and stakeholder review
|
- [ ] Team and stakeholder review
|
||||||
- [ ] Visual Design
|
- [ ] Specs reviewed and created or adjusted
|
||||||
- [ ] Team review
|
- [ ] Implementation
|
||||||
- [ ] Etc.
|
- [ ] Testing (unit and/or e2e)
|
||||||
|
- [ ] Code review
|
||||||
|
- [ ] QA review
|
||||||
|
|
||||||
## Sketch
|
## Sketch
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ jobs:
|
|||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
steps:
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
@@ -27,14 +32,16 @@ jobs:
|
|||||||
|
|
||||||
- name: resolve ipfs hashes for release
|
- name: resolve ipfs hashes for release
|
||||||
run: |
|
run: |
|
||||||
echo "Tag name: ${{ github.event.release.tag_name }}"
|
|
||||||
echo "Name: ${{ github.event.release.name }}"
|
echo "Name: ${{ github.event.release.name }}"
|
||||||
echo "Description: ${{ github.event.release.body }}"
|
echo "Description: ${{ github.event.release.body }}"
|
||||||
until docker pull vegaprotocol/trading:${{ github.event.release.tag_name }}; do
|
echo "Tag: ${{ github.event.release.tag_name }}"
|
||||||
|
commit="$(git rev-list -n 1 ${{ github.event.release.tag_name }})"
|
||||||
|
echo "Commit: $commit"
|
||||||
|
until docker pull vegaprotocol/trading:$commit; do
|
||||||
echo "Image not pushed yet, waiting 60 seconds"
|
echo "Image not pushed yet, waiting 60 seconds"
|
||||||
sleep 60
|
sleep 60
|
||||||
done
|
done
|
||||||
docker run --rm vegaprotocol/trading:${{ github.event.release.tag_name }} cat /ipfs-hash > ipfs-hash
|
docker run --rm vegaprotocol/trading:$commit cat /ipfs-hash > ipfs-hash
|
||||||
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
|
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
|
tar -xzf kubo.tgz
|
||||||
export PATH="$PATH:$PWD/kubo"
|
export PATH="$PATH:$PWD/kubo"
|
||||||
@@ -56,12 +63,12 @@ jobs:
|
|||||||
* https://governance.vega.xyz
|
* https://governance.vega.xyz
|
||||||
|
|
||||||
# IPFS releases
|
# IPFS releases
|
||||||
Tye IPFS hash of this release of the Trading app is:
|
The IPFS hash of this release of the Trading app is:
|
||||||
|
|
||||||
CIDv0: ${{ env.IPFS_V0 }}
|
CIDv0: ${{ env.IPFS_V0 }}
|
||||||
CIDv1: ${{ env.IPFS_V1 }}
|
CIDv1: ${{ env.IPFS_V1 }}
|
||||||
|
|
||||||
You can always access the latest IPFS release by visiting [vega.trading](https://vega.trading).
|
You can always access the latest IPFS release by visiting [console.vega.xyz](https://console.vega.xyz).
|
||||||
|
|
||||||
You can also access Trading directly from an IPFS gateway.
|
You can also access Trading directly from an IPFS gateway.
|
||||||
BEWARE: The Trading interface uses [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to remember your settings, such as which tokens you have imported. You should always use an IPFS gateway that enforces [origin separation](https://ipfs.github.io/public-gateway-checker/).
|
BEWARE: The Trading interface uses [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to remember your settings, such as which tokens you have imported. You should always use an IPFS gateway that enforces [origin separation](https://ipfs.github.io/public-gateway-checker/).
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- release/*
|
- release/*
|
||||||
- develop
|
- develop
|
||||||
tags:
|
- main
|
||||||
- v*
|
# uncomment pull_request and comment pull_request_target to test CI changes against feature branch not target branch (develop)
|
||||||
pull_request:
|
# pull_request:
|
||||||
|
pull_request_target:
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
- ready_for_review
|
- ready_for_review
|
||||||
@@ -21,6 +22,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Cache node modules
|
- name: Cache node modules
|
||||||
id: cache
|
id: cache
|
||||||
@@ -61,6 +64,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
@@ -108,35 +112,86 @@ jobs:
|
|||||||
echo "Branch slug: ${branch_slug}"
|
echo "Branch slug: ${branch_slug}"
|
||||||
echo ">>>> eof debug"
|
echo ">>>> eof debug"
|
||||||
|
|
||||||
projects_e2e=""
|
projects_array=()
|
||||||
|
|
||||||
preview_governance="not deployed"
|
preview_governance="not deployed"
|
||||||
preview_trading="not deployed"
|
preview_trading="not deployed"
|
||||||
preview_explorer="not deployed"
|
preview_explorer="not deployed"
|
||||||
if [[ $affected == *"governance"* ]]; then
|
preview_tools="not deployed"
|
||||||
projects_e2e+='"governance-e2e" '
|
|
||||||
|
# parse if affected is any of three main applications, if none - use all of them
|
||||||
|
if echo "$affected" | grep -q governance; then
|
||||||
|
echo "Governance is affected"
|
||||||
|
projects_array+=("governance")
|
||||||
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
||||||
fi
|
fi
|
||||||
if [[ $affected == *"trading"* ]]; then
|
if echo "$affected" | grep -q trading; then
|
||||||
projects_e2e+='"trading-e2e" '
|
echo "Trading is affected"
|
||||||
|
projects_array+=("trading")
|
||||||
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
||||||
fi
|
fi
|
||||||
if [[ $affected == *"explorer"* ]]; then
|
if echo "$affected" | grep -q explorer; then
|
||||||
projects_e2e+='"explorer-e2e" '
|
echo "Explorer is affected"
|
||||||
|
projects_array+=("explorer")
|
||||||
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
||||||
fi
|
fi
|
||||||
if [[ -z "$projects_e2e" ]]; then
|
if [[ ${#projects_array[@]} -eq 0 ]]; then
|
||||||
projects_e2e+='"governance-e2e" "trading-e2e" "explorer-e2e" '
|
projects_array=("governance" "trading" "explorer")
|
||||||
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
||||||
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
||||||
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
||||||
fi
|
fi
|
||||||
projects_e2e=${projects_e2e%?}
|
|
||||||
projects_e2e=[${projects_e2e// /,}]
|
# applications parsed before this loop are applicable for running e2e-tests
|
||||||
echo PROJECTS_E2E=$projects_e2e >> $GITHUB_ENV
|
projects_e2e_array=()
|
||||||
echo PROJECTS=$(echo $projects_e2e | sed 's|-e2e||g') >> $GITHUB_ENV
|
for project in "${projects_array[@]}"; do
|
||||||
|
projects_e2e_array+=("${project}-e2e")
|
||||||
|
done
|
||||||
|
# all applications below this loop are not applicable for running e2e-test
|
||||||
|
|
||||||
|
# check if pull request event to deploy tools
|
||||||
|
if [[ "${{ github.event_name }}" = "pull_request" ]]; then
|
||||||
|
if echo "$affected" | grep -q multisig-signer; then
|
||||||
|
echo "Tools are affected"
|
||||||
|
echo "Deploying tools on preview"
|
||||||
|
preview_tools=$(printf "https://%s.%s.vega.rocks" "tools" "$branch_slug")
|
||||||
|
|
||||||
|
projects_array+=("multisig-signer")
|
||||||
|
fi
|
||||||
|
# those apps deploy only from develop to mainnet
|
||||||
|
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||||
|
if echo "$affected" | grep -q multisig-signer; then
|
||||||
|
echo "Tools are affected"
|
||||||
|
echo "Deploying tools on s3"
|
||||||
|
|
||||||
|
projects_array+=("multisig-signer")
|
||||||
|
fi
|
||||||
|
if echo "$affected" | grep -q static; then
|
||||||
|
echo "static is affected"
|
||||||
|
echo "Deploying static on s3"
|
||||||
|
|
||||||
|
projects_array+=("static")
|
||||||
|
fi
|
||||||
|
if echo "$affected" | grep -q ui-toolkit; then
|
||||||
|
echo "ui-toolkit is affected"
|
||||||
|
echo "Deploying ui-toolkit on s3"
|
||||||
|
|
||||||
|
projects_array+=("ui-toolkit")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Projects: ${projects_array[@]}"
|
||||||
|
echo "Projects E2E: ${projects_e2e_array[@]}"
|
||||||
|
projects_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_array[@]}")
|
||||||
|
projects_e2e_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_e2e_array[@]}")
|
||||||
|
|
||||||
|
echo PROJECTS_E2E=$projects_e2e_json >> $GITHUB_ENV
|
||||||
|
echo PROJECTS=$projects_json >> $GITHUB_ENV
|
||||||
|
|
||||||
echo PREVIEW_GOVERNANCE=$preview_governance >> $GITHUB_ENV
|
echo PREVIEW_GOVERNANCE=$preview_governance >> $GITHUB_ENV
|
||||||
echo PREVIEW_TRADING=$preview_trading >> $GITHUB_ENV
|
echo PREVIEW_TRADING=$preview_trading >> $GITHUB_ENV
|
||||||
echo PREVIEW_EXPLORER=$preview_explorer >> $GITHUB_ENV
|
echo PREVIEW_EXPLORER=$preview_explorer >> $GITHUB_ENV
|
||||||
|
echo PREVIEW_TOOLS=$preview_tools >> $GITHUB_ENV
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
projects: ${{ env.PROJECTS }}
|
projects: ${{ env.PROJECTS }}
|
||||||
@@ -144,11 +199,12 @@ jobs:
|
|||||||
preview_governance: ${{ env.PREVIEW_GOVERNANCE }}
|
preview_governance: ${{ env.PREVIEW_GOVERNANCE }}
|
||||||
preview_trading: ${{ env.PREVIEW_TRADING }}
|
preview_trading: ${{ env.PREVIEW_TRADING }}
|
||||||
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
||||||
|
preview_tools: ${{ env.PREVIEW_TOOLS }}
|
||||||
|
|
||||||
cypress:
|
cypress:
|
||||||
needs: lint-test-build
|
needs: lint-test-build
|
||||||
name: '(CI) cypress'
|
name: '(CI) cypress'
|
||||||
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
|
if: ${{ needs.lint-test-build.outputs.projects-e2e != '[]' }}
|
||||||
uses: ./.github/workflows/cypress-run.yml
|
uses: ./.github/workflows/cypress-run.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
@@ -170,6 +226,7 @@ jobs:
|
|||||||
- publish-dist
|
- publish-dist
|
||||||
- lint-test-build
|
- lint-test-build
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
timeout-minutes: 60
|
||||||
name: '(CD) comment preview links'
|
name: '(CD) comment preview links'
|
||||||
steps:
|
steps:
|
||||||
- name: Find Comment
|
- name: Find Comment
|
||||||
@@ -179,6 +236,35 @@ jobs:
|
|||||||
issue-number: ${{ github.event.pull_request.number }}
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
body-includes: Previews
|
body-includes: Previews
|
||||||
|
|
||||||
|
- name: Wait for deployments
|
||||||
|
run: |
|
||||||
|
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url
|
||||||
|
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
|
||||||
|
if [[ "${{ needs.lint-test-build.outputs.preview_governance }}" =~ $regex ]]; then
|
||||||
|
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do
|
||||||
|
echo "waiting for governance preview"
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [[ "${{ needs.lint-test-build.outputs.preview_explorer }}" =~ $regex ]]; then
|
||||||
|
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do
|
||||||
|
echo "waiting for explorer preview"
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [[ "${{ needs.lint-test-build.outputs.preview_trading }}" =~ $regex ]]; then
|
||||||
|
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do
|
||||||
|
echo "waiting for trading preview"
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [[ "${{ needs.lint-test-build.outputs.preview_tools }}" =~ $regex ]]; then
|
||||||
|
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do
|
||||||
|
echo "waiting for tools preview"
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Create comment
|
- name: Create comment
|
||||||
uses: peter-evans/create-or-update-comment@v3
|
uses: peter-evans/create-or-update-comment@v3
|
||||||
if: ${{ steps.fc.outputs.comment-id == 0 }}
|
if: ${{ steps.fc.outputs.comment-id == 0 }}
|
||||||
@@ -189,16 +275,11 @@ jobs:
|
|||||||
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
|
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
|
||||||
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
|
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
|
||||||
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
|
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
|
||||||
|
* tools: ${{ needs.lint-test-build.outputs.preview_tools }}
|
||||||
cypress-check:
|
|
||||||
name: '(CI) cypress - check'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: cypress
|
|
||||||
steps:
|
|
||||||
- run: echo Done!
|
|
||||||
|
|
||||||
# Report single result at the end, to avoid mess with required checks in PR
|
# Report single result at the end, to avoid mess with required checks in PR
|
||||||
cypress-result:
|
cypress-check:
|
||||||
|
name: '(CI) cypress - check'
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
needs: cypress
|
needs: cypress
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
project: ${{ fromJSON(inputs.projects) }}
|
project: ${{ fromJSON(inputs.projects) }}
|
||||||
name: ${{ matrix.project }}
|
name: ${{ matrix.project }}
|
||||||
runs-on: self-hosted-runner
|
runs-on: self-hosted-runner
|
||||||
timeout-minutes: 60
|
timeout-minutes: 100
|
||||||
steps:
|
steps:
|
||||||
# Checks if skip cache was requested
|
# Checks if skip cache was requested
|
||||||
- name: Set skip-nx-cache flag
|
- name: Set skip-nx-cache flag
|
||||||
@@ -33,6 +33,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
path: './frontend-monorepo'
|
path: './frontend-monorepo'
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
# Restore node_modules from cache if possible
|
# Restore node_modules from cache if possible
|
||||||
- name: Restore node_modules from cache
|
- name: Restore node_modules from cache
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
id: quemu
|
id: quemu
|
||||||
@@ -31,6 +33,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
- name: Log in to the Container registry (ghcr)
|
- name: Log in to the Container registry (ghcr)
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
@@ -39,7 +42,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Log in to the Container registry (docker hub)
|
- name: Log in to the Container registry (docker hub)
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
||||||
with:
|
with:
|
||||||
# registry: registry.hub.docker.com
|
# registry: registry.hub.docker.com
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
@@ -70,18 +73,32 @@ jobs:
|
|||||||
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
|
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
|
||||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||||
envName="stagnet1"
|
envName="stagnet1"
|
||||||
|
if [[ "${{ matrix.app }}" = "multisig-signer" ]]; then
|
||||||
|
envName="mainnet"
|
||||||
|
bucketName="tools.vega.xyz"
|
||||||
|
fi
|
||||||
|
if [[ "${{ matrix.app }}" = "static" ]]; then
|
||||||
|
envName="mainnet"
|
||||||
|
bucketName="static.vega.xyz"
|
||||||
|
fi
|
||||||
|
if [[ "${{ matrix.app }}" = "ui-toolkit" ]]; then
|
||||||
|
envName="mainnet"
|
||||||
|
bucketName="ui.vega.rocks"
|
||||||
|
fi
|
||||||
elif [[ "${{ github.ref }}" =~ .*main$ ]]; then
|
elif [[ "${{ github.ref }}" =~ .*main$ ]]; then
|
||||||
envName="mainnet"
|
envName="mainnet"
|
||||||
elif [[ "${{ matrix.app}}" = "trading" ]] && [[ "${{ startsWith(github.ref, 'refs/tags/v') && 'true' || 'false' }}" = "true" ]]; then
|
|
||||||
envName="mainnet"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${envName}" = "mainnet" ]]; then
|
if [[ "${envName}" = "mainnet" ]]; then
|
||||||
domain="vega.xyz"
|
domain="vega.xyz"
|
||||||
bucketName="${{ matrix.app }}.${domain}"
|
if [[ -z "${bucketName}" ]]; then
|
||||||
|
bucketName="${{ matrix.app }}.${domain}"
|
||||||
|
fi
|
||||||
elif [[ "${envName}" = "testnet" ]]; then
|
elif [[ "${envName}" = "testnet" ]]; then
|
||||||
domain="fairground.wtf"
|
domain="fairground.wtf"
|
||||||
bucketName="${{ matrix.app }}.${domain}"
|
if [[ -z "${bucketName}" ]]; then
|
||||||
|
bucketName="${{ matrix.app }}.${domain}"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "${bucketName}" ]]; then
|
if [[ -z "${bucketName}" ]]; then
|
||||||
@@ -98,14 +115,15 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
flags=""
|
flags=""
|
||||||
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
|
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
|
||||||
if [[ "${{ env.ENV_NAME }}" != "ops-vega" ]]; then
|
flags="--env=${{ env.ENV_NAME }}"
|
||||||
flags="--env=${{ env.ENV_NAME }}"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${{ matrix.app }}" = "trading" ]; then
|
if [ "${{ matrix.app }}" = "trading" ]; then
|
||||||
yarn nx export trading $flags || (yarn install && yarn nx export trading $flags)
|
yarn nx export trading $flags || (yarn install && yarn nx export trading $flags)
|
||||||
DIST_LOCATION=dist/apps/trading/exported
|
DIST_LOCATION=dist/apps/trading/exported
|
||||||
|
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
||||||
|
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
||||||
|
DIST_LOCATION=dist/storybook/ui-toolkit
|
||||||
else
|
else
|
||||||
yarn nx build ${{ matrix.app }} $flags || (yarn install && yarn nx build ${{ matrix.app }} $flags)
|
yarn nx build ${{ matrix.app }} $flags || (yarn install && yarn nx build ${{ matrix.app }} $flags)
|
||||||
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
||||||
@@ -140,7 +158,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Publish dist as docker image (ghcr)
|
- name: Publish dist as docker image (ghcr)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
if: ${{ github.event_name == 'pull_request' || (matrix.app == 'trading' && github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/v') ) }}
|
continue-on-error: true
|
||||||
|
id: ghcr-push
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/node-outside-docker.Dockerfile
|
file: docker/node-outside-docker.Dockerfile
|
||||||
@@ -153,7 +173,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Publish dist as docker image (docker hub)
|
- name: Publish dist as docker image (docker hub)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
|
continue-on-error: true
|
||||||
|
id: dockerhub-push
|
||||||
|
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/node-outside-docker.Dockerfile
|
file: docker/node-outside-docker.Dockerfile
|
||||||
@@ -162,13 +184,41 @@ jobs:
|
|||||||
APP=${{ matrix.app }}
|
APP=${{ matrix.app }}
|
||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.ref_name }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:mainnet
|
vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
|
||||||
|
|
||||||
|
- name: Publish dist as docker image (ghcr - retry)
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
if: ${{ steps.ghcr-push.outcome == 'failure' }}
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: docker/node-outside-docker.Dockerfile
|
||||||
|
push: true
|
||||||
|
build-args: |
|
||||||
|
APP=${{ matrix.app }}
|
||||||
|
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 - retry)
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
if: ${{ steps.dockerhub-push.outcome == 'failure' }}
|
||||||
|
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.sha }}
|
||||||
|
vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
|
||||||
|
|
||||||
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
||||||
- name: Publish dist to s3
|
- name: Publish dist to s3
|
||||||
uses: jakejarvis/s3-sync-action@master
|
uses: jakejarvis/s3-sync-action@master
|
||||||
if: ${{ github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/v') && ( matrix.app != 'trading' || (matrix.app == 'trading' && !endsWith(github.ref, 'main') ) ) }}
|
# s3 releases are not happening for trading on mainnet - it's IPFS
|
||||||
|
if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
|
||||||
with:
|
with:
|
||||||
args: --acl private --follow-symlinks --delete
|
args: --acl private --follow-symlinks --delete
|
||||||
env:
|
env:
|
||||||
@@ -186,23 +236,51 @@ jobs:
|
|||||||
number: ${{ github.event.number }}
|
number: ${{ github.event.number }}
|
||||||
|
|
||||||
- name: Trigger fleek deployment
|
- name: Trigger fleek deployment
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
|
# release to ipfs happens only on mainnet (represented by main branch) for trading
|
||||||
|
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
||||||
run: |
|
run: |
|
||||||
# display info about app
|
if echo ${{ github.ref }} | grep -q main; then
|
||||||
curl -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
# display info about app
|
||||||
-H "Content-Type: application/json" \
|
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||||
-d '{"query": "query{getSiteById(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id latestDeploy{id status}}}"}' \
|
-H "Content-Type: application/json" \
|
||||||
https://api.fleek.co/graphql
|
-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
|
# trigger new deployment as base image is always set to vegaprotocol/trading:mainnet
|
||||||
curl -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
||||||
https://api.fleek.co/graphql
|
https://api.fleek.co/graphql
|
||||||
|
|
||||||
- name: Update vega.trading DNS to redirect to the new console
|
elif echo ${{ github.ref }} | grep -q release/testnet; then
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
|
# display info about app
|
||||||
|
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"query": "query{getSiteById(siteId:\"79baaeca-1952-4ae7-a256-f668cfc1d68e\"){id latestDeploy{id status}}}"}' \
|
||||||
|
https://api.fleek.co/graphql
|
||||||
|
|
||||||
|
# trigger new deployment as base image is always set to vegaprotocol/trading:mainnet
|
||||||
|
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"query": "mutation{triggerDeploy(siteId:\"79baaeca-1952-4ae7-a256-f668cfc1d68e\"){id status}}"}' \
|
||||||
|
https://api.fleek.co/graphql
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Check out ipfs-redirect
|
||||||
|
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: 'vegaprotocol/ipfs-redirect'
|
||||||
|
path: 'ipfs-redirect'
|
||||||
|
fetch-depth: '0'
|
||||||
|
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Update interstitial page to point to the new console
|
||||||
|
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
|
# set CID
|
||||||
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
|
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
|
tar -xzf kubo.tgz
|
||||||
export PATH="$PATH:$PWD/kubo"
|
export PATH="$PATH:$PWD/kubo"
|
||||||
@@ -210,26 +288,28 @@ jobs:
|
|||||||
new_hash=$(cat ${{ matrix.app }}-ipfs-hash)
|
new_hash=$(cat ${{ matrix.app }}-ipfs-hash)
|
||||||
new_cid=$(ipfs cid format -v 1 -b base32 $new_hash)
|
new_cid=$(ipfs cid format -v 1 -b base32 $new_hash)
|
||||||
|
|
||||||
# Generate console URL
|
(
|
||||||
new_console_url_type=ipfs
|
cd ipfs-redirect
|
||||||
# new_console_url_type=ipns
|
|
||||||
new_console_url_domain=cf-ipfs.com
|
|
||||||
# new_console_url_domain=dweb.link
|
|
||||||
new_console_url="https://${new_cid}.${new_console_url_type}.${new_console_url_domain}/"
|
|
||||||
echo "new_console_url=${new_console_url}"
|
|
||||||
|
|
||||||
# Update record in DNSimple
|
# configure git
|
||||||
# docs: https://developer.dnsimple.com/v2/zones/records/#updateZoneRecord
|
git status
|
||||||
dnsimple_account_id=84895
|
cat .git/config
|
||||||
dnsimple_zone_name=vega.trading
|
git config --global user.email "vega-ci-bot@vega.xyz"
|
||||||
dnsimple_record_id=44409591
|
git config --global user.name "vega-ci-bot"
|
||||||
# see: https://dnsimple.com/a/84895/domains/vega.trading/records/44409591/edit
|
|
||||||
|
|
||||||
curl -H 'Authorization: Bearer ${{ secrets.DNSIMPLE_API_TOKEN }}' \
|
# update CID files
|
||||||
-H 'Accept: application/json' \
|
if echo ${{ github.ref }} | grep -q main; then
|
||||||
-H 'Content-Type: application/json' \
|
echo $new_hash > cidv0-mainnet.txt
|
||||||
-X PATCH \
|
echo $new_cid > cidv1-mainnet.txt
|
||||||
-d "{
|
git add cidv0-mainnet.txt cidv1-mainnet.txt
|
||||||
\"content\": \"${new_console_url}\"
|
elif echo ${{ github.ref }} | grep -q release/testnet; then
|
||||||
}" \
|
echo $new_hash > cidv0-fairground.txt
|
||||||
https://api.dnsimple.com/v2/${dnsimple_account_id}/zones/${dnsimple_zone_name}/records/${dnsimple_record_id}
|
echo $new_cid > cidv1-fairground.txt
|
||||||
|
git add cidv0-fairground.txt cidv1-fairground.txt
|
||||||
|
fi
|
||||||
|
|
||||||
|
# create commit
|
||||||
|
commit_msg="Automated hash update from ${{ github.ref }}"
|
||||||
|
git commit -m "$commit_msg"
|
||||||
|
git push -u origin "main"
|
||||||
|
)
|
||||||
|
|||||||
@@ -43,7 +43,17 @@ jobs:
|
|||||||
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
||||||
https://api.fleek.co/graphql
|
https://api.fleek.co/graphql
|
||||||
|
|
||||||
- name: Update vega.trading DNS to redirect to the new console
|
- name: Check out ipfs-redirect
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: 'vegaprotocol/ipfs-redirect'
|
||||||
|
path: 'ipfs-redirect'
|
||||||
|
fetch-depth: '0'
|
||||||
|
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Update console.vega.xyz DNS to redirect to the new console
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
|
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
|
tar -xzf kubo.tgz
|
||||||
@@ -51,27 +61,24 @@ jobs:
|
|||||||
which ipfs
|
which ipfs
|
||||||
new_hash=$(cat ipfs-hash)
|
new_hash=$(cat ipfs-hash)
|
||||||
new_cid=$(ipfs cid format -v 1 -b base32 $new_hash)
|
new_cid=$(ipfs cid format -v 1 -b base32 $new_hash)
|
||||||
|
git config --global user.email "vega-ci-bot@vega.xyz"
|
||||||
|
git config --global user.name "vega-ci-bot"
|
||||||
|
echo $new_hash > ipfs-redirect/cidv0.txt
|
||||||
|
echo $new_cid > ipfs-redirect/cidv1.txt
|
||||||
|
|
||||||
# Generate console URL
|
(
|
||||||
new_console_url_type=ipfs
|
cd ipfs-redirect
|
||||||
# new_console_url_type=ipns
|
|
||||||
new_console_url_domain=cf-ipfs.com
|
|
||||||
# new_console_url_domain=dweb.link
|
|
||||||
new_console_url="https://${new_cid}.${new_console_url_type}.${new_console_url_domain}/"
|
|
||||||
echo "new_console_url=${new_console_url}"
|
|
||||||
|
|
||||||
# Update record in DNSimple
|
git status
|
||||||
# docs: https://developer.dnsimple.com/v2/zones/records/#updateZoneRecord
|
branch_name="rollback-to-$new_hash"
|
||||||
dnsimple_account_id=84895
|
git checkout -b "$branch_name"
|
||||||
dnsimple_zone_name=vega.trading
|
commit_msg="hash rollback to $new_hash"
|
||||||
dnsimple_record_id=44409591
|
git add cidv0.txt cidv1.txt
|
||||||
# see: https://dnsimple.com/a/84895/domains/vega.trading/records/44409591/edit
|
git commit -m "$commit_msg"
|
||||||
|
git push -u origin "$branch_name" --force-with-lease
|
||||||
curl -H 'Authorization: Bearer ${{ secrets.DNSIMPLE_API_TOKEN }}' \
|
pr_url="$(gh pr create --title "${commit_msg}" --body 'automated pull request to update CIDs')"
|
||||||
-H 'Accept: application/json' \
|
echo $pr_url
|
||||||
-H 'Content-Type: application/json' \
|
# once auto merge get's enabled on documentation repo let's do follow up
|
||||||
-X PATCH \
|
sleep 5
|
||||||
-d "{
|
gh pr merge "${pr_url}" --delete-branch --squash --admin
|
||||||
\"content\": \"${new_console_url}\"
|
)
|
||||||
}" \
|
|
||||||
https://api.dnsimple.com/v2/${dnsimple_account_id}/zones/${dnsimple_zone_name}/records/${dnsimple_record_id}
|
|
||||||
|
|||||||
@@ -50,3 +50,5 @@ cypress.env.json
|
|||||||
|
|
||||||
#cypress
|
#cypress
|
||||||
/apps/**/cypress/reports/
|
/apps/**/cypress/reports/
|
||||||
|
/apps/**/cypress/downloads/
|
||||||
|
/apps/**/fixtures/wallet/node**
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
|
||||||
NX_TENDERMINT_URL=http://localhost:26617
|
NX_TENDERMINT_URL=http://localhost:26617
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||||
NX_VEGA_URL=http://localhost:3008/graphql
|
NX_VEGA_URL=http://localhost:3008/graphql
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
|
||||||
NX_TENDERMINT_URL=https://n04.d.vega.xyz/tm
|
NX_TENDERMINT_URL=https://n04.d.vega.xyz/tm
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket
|
||||||
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
|
||||||
NX_TENDERMINT_URL=https://mainnet-observer-proxy01.ops.vega.xyz/
|
NX_TENDERMINT_URL=https://mainnet-observer-proxy01.ops.vega.xyz/
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocket
|
||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
|
||||||
NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz/tm
|
NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz/tm
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
|
||||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||||
|
|||||||
+2
-1
@@ -12,9 +12,10 @@ NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest
|
|||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.stagnet1.vega.rocks
|
NX_VEGA_GOVERNANCE_URL=https://governance.stagnet1.vega.rocks
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.jsoo
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||||
|
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases/tag/
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ NX_SENTRY_DSN=https://b3a56b03eda842faad731f3ea9dfd1bc@o286262.ingest.sentry.io/
|
|||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
NX_VEGA_ENV=MAINNET
|
NX_VEGA_ENV=MAINNET
|
||||||
NX_BLOCK_EXPLORER=https://be.vega.community/rest/
|
NX_BLOCK_EXPLORER=https://be.vega.community/rest
|
||||||
NX_ETHERSCAN_URL=https://etherscan.io
|
NX_ETHERSCAN_URL=https://etherscan.io
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
||||||
NX_VEGA_CONSOLE_URL=https://vega.trading
|
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
# .env is stagnet1, so there are no overrides required
|
# .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"}'
|
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}'
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
"executor": "@nrwl/workspace:run-commands",
|
"executor": "@nrwl/workspace:run-commands",
|
||||||
"options": {
|
"options": {
|
||||||
"commands": [
|
"commands": [
|
||||||
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.67.3/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.71.4/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,29 +1,13 @@
|
|||||||
import WS from 'jest-websocket-mock';
|
import WS from 'jest-websocket-mock';
|
||||||
import useWebSocket from 'react-use-websocket';
|
import { render, screen } from '@testing-library/react';
|
||||||
import {
|
|
||||||
render,
|
|
||||||
screen,
|
|
||||||
fireEvent,
|
|
||||||
act,
|
|
||||||
waitFor,
|
|
||||||
} from '@testing-library/react';
|
|
||||||
import { TendermintWebsocketContext } from '../../contexts/websocket/tendermint-websocket-context';
|
|
||||||
import { BlocksRefetch } from './blocks-refetch';
|
import { BlocksRefetch } from './blocks-refetch';
|
||||||
|
|
||||||
const BlocksRefetchInWebsocketProvider = ({
|
const BlocksRefetchInWebsocketProvider = ({
|
||||||
callback,
|
callback,
|
||||||
mocketLocation,
|
|
||||||
}: {
|
}: {
|
||||||
callback: () => null;
|
callback: () => null;
|
||||||
mocketLocation: string;
|
|
||||||
}) => {
|
}) => {
|
||||||
const contextShape = useWebSocket(mocketLocation);
|
return <BlocksRefetch refetch={callback} />;
|
||||||
|
|
||||||
return (
|
|
||||||
<TendermintWebsocketContext.Provider value={{ ...contextShape }}>
|
|
||||||
<BlocksRefetch refetch={callback} />
|
|
||||||
</TendermintWebsocketContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Blocks refetch', () => {
|
describe('Blocks refetch', () => {
|
||||||
@@ -32,111 +16,8 @@ describe('Blocks refetch', () => {
|
|||||||
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
||||||
new WebSocket(mocketLocation);
|
new WebSocket(mocketLocation);
|
||||||
|
|
||||||
render(
|
render(<BlocksRefetchInWebsocketProvider callback={() => null} />);
|
||||||
<BlocksRefetchInWebsocketProvider
|
|
||||||
callback={() => null}
|
|
||||||
mocketLocation={mocketLocation}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
await mocket.connected;
|
|
||||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('new blocks');
|
|
||||||
expect(screen.getByTestId('refresh')).toBeInTheDocument();
|
expect(screen.getByTestId('refresh')).toBeInTheDocument();
|
||||||
mocket.close();
|
mocket.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should initiate callback when the button is clicked', async () => {
|
|
||||||
const mocketLocation = 'wss:localhost:3003';
|
|
||||||
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
|
||||||
new WebSocket(mocketLocation);
|
|
||||||
|
|
||||||
const callback = jest.fn();
|
|
||||||
render(
|
|
||||||
<BlocksRefetchInWebsocketProvider
|
|
||||||
callback={callback}
|
|
||||||
mocketLocation={mocketLocation}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
await mocket.connected;
|
|
||||||
const button = screen.getByTestId('refresh');
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
fireEvent.click(button);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(callback.mock.calls.length).toEqual(1);
|
|
||||||
mocket.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show new blocks as websocket is correctly updated', async () => {
|
|
||||||
const mocketLocation = 'wss:localhost:3004';
|
|
||||||
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
|
||||||
new WebSocket(mocketLocation);
|
|
||||||
render(
|
|
||||||
<BlocksRefetchInWebsocketProvider
|
|
||||||
callback={() => null}
|
|
||||||
mocketLocation={mocketLocation}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
await mocket.connected;
|
|
||||||
|
|
||||||
// Ensuring we send an ID equal to the one the client subscribed with.
|
|
||||||
await waitFor(() => expect(mocket.messages.length).toEqual(1));
|
|
||||||
// @ts-ignore id on messages
|
|
||||||
const id = mocket.messages[0].id;
|
|
||||||
|
|
||||||
const newBlockMessage = {
|
|
||||||
id,
|
|
||||||
result: {
|
|
||||||
query: "tm.event = 'NewBlock'",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('0 new blocks');
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
mocket.send(newBlockMessage);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('1 new blocks');
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
mocket.send(newBlockMessage);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('2 new blocks');
|
|
||||||
mocket.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('will not show new blocks if websocket has wrong ID', async () => {
|
|
||||||
const mocketLocation = 'wss:localhost:3005';
|
|
||||||
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
|
||||||
new WebSocket(mocketLocation);
|
|
||||||
|
|
||||||
render(
|
|
||||||
<BlocksRefetchInWebsocketProvider
|
|
||||||
callback={() => null}
|
|
||||||
mocketLocation={mocketLocation}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
await mocket.connected;
|
|
||||||
|
|
||||||
// Ensuring we send an ID equal to the one the client subscribed with.
|
|
||||||
await waitFor(() => expect(mocket.messages.length).toEqual(1));
|
|
||||||
|
|
||||||
const newBlockMessageBadId = {
|
|
||||||
id: 'blahblahblah',
|
|
||||||
result: {
|
|
||||||
query: "tm.event = 'NewBlock'",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('0 new blocks');
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
mocket.send(newBlockMessageBadId);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('0 new blocks');
|
|
||||||
mocket.close();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,36 +1,19 @@
|
|||||||
import { useState, useEffect } from 'react';
|
|
||||||
import { useTendermintWebsocket } from '../../hooks/use-tendermint-websocket';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { Button, Icon } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
interface BlocksRefetchProps {
|
interface BlocksRefetchProps {
|
||||||
refetch: () => void;
|
refetch: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BlocksRefetch = ({ refetch }: BlocksRefetchProps) => {
|
export const BlocksRefetch = ({ refetch }: BlocksRefetchProps) => {
|
||||||
const [blocksToLoad, setBlocksToLoad] = useState<number>(0);
|
|
||||||
|
|
||||||
const { messages } = useTendermintWebsocket({
|
|
||||||
query: "tm.event = 'NewBlock'",
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (messages.length > 0) {
|
|
||||||
setBlocksToLoad((prev) => prev + 1);
|
|
||||||
}
|
|
||||||
}, [messages]);
|
|
||||||
|
|
||||||
const refresh = () => {
|
const refresh = () => {
|
||||||
refetch();
|
refetch();
|
||||||
setBlocksToLoad(0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-4">
|
<Button onClick={refresh} data-testid="refresh" size="xs">
|
||||||
<span data-testid="new-blocks">{blocksToLoad} new blocks - </span>
|
<Icon name="refresh" className="!align-baseline mr-2" size={3} />
|
||||||
<ButtonLink onClick={refresh} data-testid="refresh">
|
{t('Load new')}
|
||||||
{t('refresh to see latest')}
|
</Button>
|
||||||
</ButtonLink>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||||
|
import { PriceMonitoringBoundsInfoPanel } from '@vegaprotocol/markets';
|
||||||
import {
|
import {
|
||||||
LiquidityInfoPanel,
|
LiquidityInfoPanel,
|
||||||
LiquidityMonitoringParametersInfoPanel,
|
LiquidityMonitoringParametersInfoPanel,
|
||||||
@@ -39,133 +40,69 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const oraclePanels = isEqual(
|
const showTwoOracles = isEqual(
|
||||||
getSigners(settlementData),
|
getSigners(settlementData),
|
||||||
getSigners(terminationData)
|
getSigners(terminationData)
|
||||||
)
|
);
|
||||||
? [
|
|
||||||
{
|
|
||||||
title: t('Settlement Oracle'),
|
|
||||||
content: (
|
|
||||||
<OracleInfoPanel
|
|
||||||
noBorder={false}
|
|
||||||
market={market}
|
|
||||||
type="settlementData"
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('Termination Oracle'),
|
|
||||||
content: (
|
|
||||||
<OracleInfoPanel
|
|
||||||
noBorder={false}
|
|
||||||
market={market}
|
|
||||||
type="termination"
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
title: t('Oracle'),
|
|
||||||
content: (
|
|
||||||
<OracleInfoPanel
|
|
||||||
noBorder={false}
|
|
||||||
market={market}
|
|
||||||
type="settlementData"
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const panels = [
|
const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2';
|
||||||
{
|
|
||||||
title: t('Key details'),
|
|
||||||
content: <KeyDetailsInfoPanel noBorder={false} market={market} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('Instrument'),
|
|
||||||
content: <InstrumentInfoPanel noBorder={false} market={market} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('Settlement asset'),
|
|
||||||
content: <SettlementAssetInfoPanel market={market} noBorder={false} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('Metadata'),
|
|
||||||
content: <MetadataInfoPanel noBorder={false} market={market} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('Risk model'),
|
|
||||||
content: <RiskModelInfoPanel noBorder={false} market={market} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('Risk parameters'),
|
|
||||||
content: <RiskParametersInfoPanel noBorder={false} market={market} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('Risk factors'),
|
|
||||||
content: <RiskFactorsInfoPanel noBorder={false} market={market} />,
|
|
||||||
},
|
|
||||||
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
|
||||||
(trigger, i) => ({
|
|
||||||
title: t(`Price monitoring trigger ${i + 1}`),
|
|
||||||
content: <MarketInfoTable noBorder={false} data={trigger} />,
|
|
||||||
})
|
|
||||||
),
|
|
||||||
...(market.data?.priceMonitoringBounds || []).map((trigger, i) => ({
|
|
||||||
title: t(`Price monitoring bound ${i + 1}`),
|
|
||||||
content: (
|
|
||||||
<>
|
|
||||||
<MarketInfoTable
|
|
||||||
noBorder={false}
|
|
||||||
data={{
|
|
||||||
maxValidPrice: trigger.maxValidPrice,
|
|
||||||
minValidPrice: trigger.minValidPrice,
|
|
||||||
}}
|
|
||||||
decimalPlaces={market.decimalPlaces}
|
|
||||||
/>
|
|
||||||
<MarketInfoTable
|
|
||||||
noBorder={false}
|
|
||||||
data={{ referencePrice: trigger.referencePrice }}
|
|
||||||
decimalPlaces={
|
|
||||||
market.tradableInstrument.instrument.product.settlementAsset
|
|
||||||
.decimals
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
})),
|
|
||||||
{
|
|
||||||
title: t('Liquidity monitoring parameters'),
|
|
||||||
content: (
|
|
||||||
<LiquidityMonitoringParametersInfoPanel
|
|
||||||
noBorder={false}
|
|
||||||
market={market}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('Liquidity'),
|
|
||||||
content: <LiquidityInfoPanel market={market} noBorder={false} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('Liquidity price range'),
|
|
||||||
content: (
|
|
||||||
<LiquidityPriceRangeInfoPanel market={market} noBorder={false} />
|
|
||||||
),
|
|
||||||
},
|
|
||||||
...oraclePanels,
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div>
|
||||||
{panels.map((p) => (
|
<h2 className={headerClassName}>{t('Key details')}</h2>
|
||||||
<div key={p.title} className="mb-3">
|
<KeyDetailsInfoPanel market={market} />
|
||||||
<h2 className="font-alpha calt text-xl">{p.title}</h2>
|
<h2 className={headerClassName}>{t('Instrument')}</h2>
|
||||||
{p.content}
|
<InstrumentInfoPanel market={market} />
|
||||||
</div>
|
<h2 className={headerClassName}>{t('Settlement asset')}</h2>
|
||||||
|
<SettlementAssetInfoPanel market={market} />
|
||||||
|
<h2 className={headerClassName}>{t('Metadata')}</h2>
|
||||||
|
<MetadataInfoPanel market={market} />
|
||||||
|
<h2 className={headerClassName}>{t('Risk model')}</h2>
|
||||||
|
<RiskModelInfoPanel market={market} />
|
||||||
|
<h2 className={headerClassName}>{t('Risk parameters')}</h2>
|
||||||
|
<RiskParametersInfoPanel market={market} />
|
||||||
|
<h2 className={headerClassName}>{t('Risk factors')}</h2>
|
||||||
|
<RiskFactorsInfoPanel market={market} />
|
||||||
|
{(market.data?.priceMonitoringBounds || []).map((trigger, i) => (
|
||||||
|
<>
|
||||||
|
<h2 className={headerClassName}>
|
||||||
|
{t('Price monitoring bounds %s', [(i + 1).toString()])}
|
||||||
|
</h2>
|
||||||
|
<PriceMonitoringBoundsInfoPanel
|
||||||
|
market={market}
|
||||||
|
triggerIndex={i + 1}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
))}
|
))}
|
||||||
</>
|
{(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
||||||
|
(trigger, i) => (
|
||||||
|
<>
|
||||||
|
<h2 className={headerClassName}>
|
||||||
|
{t('Price monitoring settings %s', [(i + 1).toString()])}
|
||||||
|
</h2>
|
||||||
|
<MarketInfoTable data={trigger} key={i} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
||||||
|
<LiquidityMonitoringParametersInfoPanel market={market} />
|
||||||
|
<h2 className={headerClassName}>{t('Liquidity')}</h2>
|
||||||
|
<LiquidityInfoPanel market={market} />
|
||||||
|
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
||||||
|
<LiquidityPriceRangeInfoPanel market={market} />
|
||||||
|
{showTwoOracles ? (
|
||||||
|
<>
|
||||||
|
<h2 className={headerClassName}>{t('Settlement oracle')}</h2>
|
||||||
|
<OracleInfoPanel market={market} type="settlementData" />
|
||||||
|
<h2 className={headerClassName}>{t('Termination oracle')}</h2>
|
||||||
|
<OracleInfoPanel market={market} type="termination" />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<h2 className={headerClassName}>{t('Oracle')}</h2>
|
||||||
|
<OracleInfoPanel market={market} type="settlementData" />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
hide={window.innerWidth <= BREAKPOINT_MD}
|
hide={window.innerWidth <= BREAKPOINT_MD}
|
||||||
valueGetter={({
|
valueGetter={({
|
||||||
data,
|
data,
|
||||||
}: VegaValueGetterParams<MarketFieldsFragment, 'state'>) => {
|
}: VegaValueGetterParams<MarketFieldsFragment>) => {
|
||||||
return data?.state ? MarketStateMapping[data?.state] : '-';
|
return data?.state ? MarketStateMapping[data?.state] : '-';
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
+6
-4
@@ -5,12 +5,13 @@ export const ErrorCodes = new Map([
|
|||||||
[51, 'Transaction failed validation'],
|
[51, 'Transaction failed validation'],
|
||||||
[60, 'Transaction could not be decoded'],
|
[60, 'Transaction could not be decoded'],
|
||||||
[70, 'Error'],
|
[70, 'Error'],
|
||||||
|
[71, 'Partial success/error'],
|
||||||
[80, 'Unknown command'],
|
[80, 'Unknown command'],
|
||||||
[89, 'Rejected as spam'],
|
[89, 'Rejected as spam'],
|
||||||
[0, 'Success'],
|
[0, 'Success'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const successCodes = new Set([0]);
|
export const successCodes = new Set([0, 71]);
|
||||||
|
|
||||||
interface ChainResponseCodeProps {
|
interface ChainResponseCodeProps {
|
||||||
code: number;
|
code: number;
|
||||||
@@ -29,11 +30,12 @@ export const ChainResponseCode = ({
|
|||||||
error,
|
error,
|
||||||
}: ChainResponseCodeProps) => {
|
}: ChainResponseCodeProps) => {
|
||||||
const isSuccess = successCodes.has(code);
|
const isSuccess = successCodes.has(code);
|
||||||
|
const successColour =
|
||||||
|
code === 71 ? 'fill-vega-orange' : 'fill-vega-green-600';
|
||||||
const icon = isSuccess ? (
|
const icon = isSuccess ? (
|
||||||
<Icon name="tick-circle" className="fill-vega-green-550" />
|
<Icon name="tick-circle" className={successColour} />
|
||||||
) : (
|
) : (
|
||||||
<Icon name="cross" className="fill-vega-pink-550" />
|
<Icon name="cross" className="fill-vega-pink-600" />
|
||||||
);
|
);
|
||||||
const label = ErrorCodes.get(code) || 'Unknown response code';
|
const label = ErrorCodes.get(code) || 'Unknown response code';
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
export interface FilterLabelProps {
|
||||||
|
filters: Set<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the list (currently limited to 1) of filters set by the
|
||||||
|
* Transaction Filter
|
||||||
|
*/
|
||||||
|
export function FilterLabel({ filters }: FilterLabelProps) {
|
||||||
|
if (!filters || filters.size !== 1) {
|
||||||
|
return <span className="uppercase">{t('Filter')}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span className="uppercase">{t('Filters')}:</span>
|
||||||
|
<code className="bg-vega-light-150 px-2 rounded-md capitalize">
|
||||||
|
{Array.from(filters)[0]}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuCheckboxItem,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItemIndicator,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuSub,
|
||||||
|
DropdownMenuSubTrigger,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
DropdownMenuSubContent,
|
||||||
|
Icon,
|
||||||
|
Button,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import type { Dispatch, SetStateAction } from 'react';
|
||||||
|
import { FilterLabel } from './tx-filter-label';
|
||||||
|
|
||||||
|
// All possible transaction types. Should be generated.
|
||||||
|
export type FilterOption =
|
||||||
|
| 'Amend LiquidityProvision Order'
|
||||||
|
| 'Amend Order'
|
||||||
|
| 'Batch Market Instructions'
|
||||||
|
| 'Cancel LiquidityProvision Order'
|
||||||
|
| 'Cancel Order'
|
||||||
|
| 'Cancel Transfer Funds'
|
||||||
|
| 'Chain Event'
|
||||||
|
| 'Delegate'
|
||||||
|
| 'Ethereum Key Rotate Submission'
|
||||||
|
| 'Issue Signatures'
|
||||||
|
| 'Key Rotate Submission'
|
||||||
|
| 'Liquidity Provision Order'
|
||||||
|
| 'Node Signature'
|
||||||
|
| 'Node Vote'
|
||||||
|
| 'Proposal'
|
||||||
|
| 'Protocol Upgrade'
|
||||||
|
| 'Register new Node'
|
||||||
|
| 'State Variable Proposal'
|
||||||
|
| 'Submit Oracle Data'
|
||||||
|
| 'Submit Order'
|
||||||
|
| 'Transfer Funds'
|
||||||
|
| 'Undelegate'
|
||||||
|
| 'Validator Heartbeat'
|
||||||
|
| 'Vote on Proposal'
|
||||||
|
| 'Withdraw';
|
||||||
|
|
||||||
|
// Alphabetised list of transaction types to appear at the top level
|
||||||
|
export const PrimaryFilterOptions: FilterOption[] = [
|
||||||
|
'Amend LiquidityProvision Order',
|
||||||
|
'Amend Order',
|
||||||
|
'Batch Market Instructions',
|
||||||
|
'Cancel LiquidityProvision Order',
|
||||||
|
'Cancel Order',
|
||||||
|
'Cancel Transfer Funds',
|
||||||
|
'Delegate',
|
||||||
|
'Liquidity Provision Order',
|
||||||
|
'Proposal',
|
||||||
|
'Submit Oracle Data',
|
||||||
|
'Submit Order',
|
||||||
|
'Transfer Funds',
|
||||||
|
'Undelegate',
|
||||||
|
'Vote on Proposal',
|
||||||
|
'Withdraw',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Alphabetised list of transaction types to nest under a 'More...' submenu
|
||||||
|
export const SecondaryFilterOptions: FilterOption[] = [
|
||||||
|
'Chain Event',
|
||||||
|
'Ethereum Key Rotate Submission',
|
||||||
|
'Issue Signatures',
|
||||||
|
'Key Rotate Submission',
|
||||||
|
'Node Signature',
|
||||||
|
'Node Vote',
|
||||||
|
'Protocol Upgrade',
|
||||||
|
'Register new Node',
|
||||||
|
'State Variable Proposal',
|
||||||
|
'Validator Heartbeat',
|
||||||
|
];
|
||||||
|
|
||||||
|
export const AllFilterOptions: FilterOption[] = [
|
||||||
|
...PrimaryFilterOptions,
|
||||||
|
...SecondaryFilterOptions,
|
||||||
|
];
|
||||||
|
|
||||||
|
export interface TxFilterProps {
|
||||||
|
filters: Set<FilterOption>;
|
||||||
|
setFilters: Dispatch<SetStateAction<Set<FilterOption>>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a structured dropdown menu of all of the available transaction
|
||||||
|
* types. It allows a user to select one transaction type to view. Later
|
||||||
|
* it will support multiple selection, but until the API supports that it is
|
||||||
|
* one or all.
|
||||||
|
* @param filters null or Set of tranaction types
|
||||||
|
* @param setFilters A function to update the filters prop
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
|
||||||
|
return (
|
||||||
|
<DropdownMenu
|
||||||
|
modal={false}
|
||||||
|
trigger={
|
||||||
|
<DropdownMenuTrigger className="ml-2">
|
||||||
|
<Button size="xs">
|
||||||
|
<FilterLabel filters={filters} />
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<DropdownMenuContent>
|
||||||
|
{filters.size > 1 ? null : (
|
||||||
|
<>
|
||||||
|
<DropdownMenuCheckboxItem
|
||||||
|
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
|
||||||
|
>
|
||||||
|
{t('Clear filters')} <Icon name="cross" />
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{PrimaryFilterOptions.map((f) => (
|
||||||
|
<DropdownMenuCheckboxItem
|
||||||
|
key={f}
|
||||||
|
checked={filters.has(f)}
|
||||||
|
onCheckedChange={() => {
|
||||||
|
// NOTE: These act like radio buttons until the API supports multiple filters
|
||||||
|
setFilters(new Set([f]));
|
||||||
|
}}
|
||||||
|
id={`radio-${f}`}
|
||||||
|
>
|
||||||
|
{f}
|
||||||
|
<DropdownMenuItemIndicator>
|
||||||
|
<Icon name="tick-circle" />
|
||||||
|
</DropdownMenuItemIndicator>
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
))}
|
||||||
|
<DropdownMenuSub>
|
||||||
|
<DropdownMenuSubTrigger>
|
||||||
|
{t('More Types')}
|
||||||
|
<Icon name="chevron-right" />
|
||||||
|
</DropdownMenuSubTrigger>
|
||||||
|
<DropdownMenuSubContent>
|
||||||
|
{SecondaryFilterOptions.map((f) => (
|
||||||
|
<DropdownMenuCheckboxItem
|
||||||
|
key={f}
|
||||||
|
checked={filters.has(f)}
|
||||||
|
onCheckedChange={(checked) => {
|
||||||
|
// NOTE: These act like radio buttons until the API supports multiple filters
|
||||||
|
setFilters(new Set([f]));
|
||||||
|
}}
|
||||||
|
id={`radio-${f}`}
|
||||||
|
>
|
||||||
|
{f}
|
||||||
|
<DropdownMenuItemIndicator>
|
||||||
|
<Icon name="tick-circle" className="inline" />
|
||||||
|
</DropdownMenuItemIndicator>
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuSubContent>
|
||||||
|
</DropdownMenuSub>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -160,6 +160,7 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
|||||||
vote={command?.voteSubmission?.value === 'VALUE_YES'}
|
vote={command?.voteSubmission?.value === 'VALUE_YES'}
|
||||||
yesText="Proposal vote"
|
yesText="Proposal vote"
|
||||||
noText="Proposal vote"
|
noText="Proposal vote"
|
||||||
|
useVoteColour={false}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { FixedSizeList as List } from 'react-window';
|
import { FixedSizeList as List } from 'react-window';
|
||||||
import InfiniteLoader from 'react-window-infinite-loader';
|
import InfiniteLoader from 'react-window-infinite-loader';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
@@ -69,6 +69,17 @@ export const TxsInfiniteList = ({
|
|||||||
}: TxsInfiniteListProps) => {
|
}: TxsInfiniteListProps) => {
|
||||||
const { screenSize } = useScreenDimensions();
|
const { screenSize } = useScreenDimensions();
|
||||||
const isStacked = ['xs', 'sm'].includes(screenSize);
|
const isStacked = ['xs', 'sm'].includes(screenSize);
|
||||||
|
const infiniteLoaderRef = useRef<InfiniteLoader>(null);
|
||||||
|
const hasMountedRef = useRef(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasMountedRef.current) {
|
||||||
|
if (infiniteLoaderRef.current) {
|
||||||
|
infiniteLoaderRef.current.resetloadMoreItemsCache(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hasMountedRef.current = true;
|
||||||
|
}, [loadMoreTxs]);
|
||||||
|
|
||||||
if (!txs) {
|
if (!txs) {
|
||||||
if (!areTxsLoading) {
|
if (!areTxsLoading) {
|
||||||
@@ -110,6 +121,7 @@ export const TxsInfiniteList = ({
|
|||||||
isItemLoaded={isItemLoaded}
|
isItemLoaded={isItemLoaded}
|
||||||
itemCount={itemCount}
|
itemCount={itemCount}
|
||||||
loadMoreItems={loadMoreItems}
|
loadMoreItems={loadMoreItems}
|
||||||
|
ref={infiniteLoaderRef}
|
||||||
>
|
>
|
||||||
{({ onItemsRendered, ref }) => (
|
{({ onItemsRendered, ref }) => (
|
||||||
<List
|
<List
|
||||||
|
|||||||
@@ -34,4 +34,17 @@ describe('Vote TX icon', () => {
|
|||||||
const no = render(<VoteIcon vote={false} />);
|
const no = render(<VoteIcon vote={false} />);
|
||||||
expect(no.getByRole('img')).toHaveAttribute('aria-label', 'delete icon');
|
expect(no.getByRole('img')).toHaveAttribute('aria-label', 'delete icon');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('useVoteColour prop can be used to override coloured background', () => {
|
||||||
|
const no = render(<VoteIcon vote={false} />);
|
||||||
|
expect(no.container.children[0]).toHaveClass('bg-vega-pink-550');
|
||||||
|
|
||||||
|
const monochromeNo = render(
|
||||||
|
<VoteIcon vote={false} useVoteColour={false} />
|
||||||
|
);
|
||||||
|
expect(monochromeNo.container.children[0]).not.toHaveClass(
|
||||||
|
'bg-vega-pink-550'
|
||||||
|
);
|
||||||
|
expect(monochromeNo.container.children[0]).toHaveClass('bg-vega-dark-200');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,6 +8,32 @@ export interface VoteIconProps {
|
|||||||
yesText?: string;
|
yesText?: string;
|
||||||
// Defaults to 'Against', but can be any text
|
// Defaults to 'Against', but can be any text
|
||||||
noText?: string;
|
noText?: string;
|
||||||
|
// If set to false the background will not be coloured
|
||||||
|
useVoteColour?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBgColour(useVoteColour: boolean, vote: boolean) {
|
||||||
|
if (useVoteColour === false) {
|
||||||
|
return 'bg-vega-dark-200';
|
||||||
|
}
|
||||||
|
|
||||||
|
return vote ? 'bg-vega-green-550' : 'bg-vega-pink-550';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFillColour(useVoteColour: boolean, vote: boolean) {
|
||||||
|
if (useVoteColour === false) {
|
||||||
|
return 'white';
|
||||||
|
}
|
||||||
|
|
||||||
|
return vote ? 'vega-green-300' : 'vega-pink-300';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTextColour(useVoteColour: boolean, vote: boolean) {
|
||||||
|
if (useVoteColour === false) {
|
||||||
|
return 'white';
|
||||||
|
}
|
||||||
|
|
||||||
|
return vote ? 'vega-green-200' : 'vega-pink-200';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,14 +44,15 @@ export interface VoteIconProps {
|
|||||||
*/
|
*/
|
||||||
export function VoteIcon({
|
export function VoteIcon({
|
||||||
vote,
|
vote,
|
||||||
|
useVoteColour = true,
|
||||||
yesText = 'For',
|
yesText = 'For',
|
||||||
noText = 'Against',
|
noText = 'Against',
|
||||||
}: VoteIconProps) {
|
}: VoteIconProps) {
|
||||||
const label = vote ? yesText : noText;
|
const label = vote ? yesText : noText;
|
||||||
const bg = vote ? 'bg-vega-green-550' : 'bg-vega-pink-550';
|
|
||||||
const icon: IconName = vote ? 'tick-circle' : 'delete';
|
const icon: IconName = vote ? 'tick-circle' : 'delete';
|
||||||
const fill = vote ? 'vega-green-300' : 'vega-pink-300';
|
const bg = getBgColour(useVoteColour, vote);
|
||||||
const text = vote ? 'vega-green-200' : 'vega-pink-200';
|
const fill = getFillColour(useVoteColour, vote);
|
||||||
|
const text = getTextColour(useVoteColour, vote);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export const getTxsDataUrl = ({ limit, filters }: IGetTxsDataUrl) => {
|
|||||||
// Hacky fix for param as array
|
// Hacky fix for param as array
|
||||||
let urlAsString = url.toString();
|
let urlAsString = url.toString();
|
||||||
if (filters) {
|
if (filters) {
|
||||||
urlAsString += '&' + filters;
|
urlAsString += '&' + filters.replace(' ', '%20');
|
||||||
}
|
}
|
||||||
|
|
||||||
return urlAsString;
|
return urlAsString;
|
||||||
@@ -65,6 +65,14 @@ export const useTxsData = ({ limit, filters }: IUseTxsData) => {
|
|||||||
}
|
}
|
||||||
}, [setTxsState, data]);
|
}, [setTxsState, data]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTxsState((prev) => ({
|
||||||
|
txsData: [],
|
||||||
|
hasMoreTxs: true,
|
||||||
|
lastCursor: '',
|
||||||
|
}));
|
||||||
|
}, [filters]);
|
||||||
|
|
||||||
const loadTxs = useCallback(() => {
|
const loadTxs = useCallback(() => {
|
||||||
return refetch({
|
return refetch({
|
||||||
limit: limit,
|
limit: limit,
|
||||||
|
|||||||
@@ -5,17 +5,43 @@ import { TxsInfiniteList } from '../../../components/txs';
|
|||||||
import { useTxsData } from '../../../hooks/use-txs-data';
|
import { useTxsData } from '../../../hooks/use-txs-data';
|
||||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||||
|
|
||||||
const BE_TXS_PER_REQUEST = 20;
|
import { useState } from 'react';
|
||||||
|
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
|
||||||
|
|
||||||
|
const BE_TXS_PER_REQUEST = 15;
|
||||||
|
|
||||||
export const TxsList = () => {
|
export const TxsList = () => {
|
||||||
useDocumentTitle(['Transactions']);
|
useDocumentTitle(['Transactions']);
|
||||||
|
|
||||||
const { hasMoreTxs, loadTxs, error, txsData, refreshTxs, loading } =
|
|
||||||
useTxsData({ limit: BE_TXS_PER_REQUEST });
|
|
||||||
return (
|
return (
|
||||||
<section className="md:p-2 lg:p-4 xl:p-6">
|
<section className="md:p-2 lg:p-4 xl:p-6 relative">
|
||||||
<RouteTitle>{t('Transactions')}</RouteTitle>
|
<RouteTitle>{t('Transactions')}</RouteTitle>
|
||||||
<BlocksRefetch refetch={refreshTxs} />
|
<TxsListFiltered />
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TxsListFiltered = () => {
|
||||||
|
const [filters, setFilters] = useState(new Set(AllFilterOptions));
|
||||||
|
|
||||||
|
const f =
|
||||||
|
filters && filters.size === 1
|
||||||
|
? `filters[cmd.type]=${Array.from(filters)[0]}`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const { hasMoreTxs, loadTxs, error, txsData, refreshTxs, loading } =
|
||||||
|
useTxsData({
|
||||||
|
limit: BE_TXS_PER_REQUEST,
|
||||||
|
filters: f,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<menu className="mb-2">
|
||||||
|
<BlocksRefetch refetch={refreshTxs} />
|
||||||
|
<TxsFilter filters={filters} setFilters={setFilters} />
|
||||||
|
</menu>
|
||||||
|
|
||||||
<TxsInfiniteList
|
<TxsInfiniteList
|
||||||
hasMoreTxs={hasMoreTxs}
|
hasMoreTxs={hasMoreTxs}
|
||||||
areTxsLoading={loading}
|
areTxsLoading={loading}
|
||||||
@@ -24,6 +50,6 @@ export const TxsList = () => {
|
|||||||
error={error}
|
error={error}
|
||||||
className="mb-28"
|
className="mb-28"
|
||||||
/>
|
/>
|
||||||
</section>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+428
-421
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@ module.exports = defineConfig({
|
|||||||
viewportWidth: 1440,
|
viewportWidth: 1440,
|
||||||
viewportHeight: 900,
|
viewportHeight: 900,
|
||||||
numTestsKeptInMemory: 5,
|
numTestsKeptInMemory: 5,
|
||||||
|
downloadsFolder: 'cypress/downloads',
|
||||||
testIsolation: false,
|
testIsolation: false,
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
@@ -48,7 +49,7 @@ module.exports = defineConfig({
|
|||||||
vegaTokenContractAddress: '0xF41bD86d462D36b997C0bbb4D97a0a3382f205B7',
|
vegaTokenContractAddress: '0xF41bD86d462D36b997C0bbb4D97a0a3382f205B7',
|
||||||
vegaTokenAddress: '0x67175Da1D5e966e40D11c4B2519392B2058373de',
|
vegaTokenAddress: '0x67175Da1D5e966e40D11c4B2519392B2058373de',
|
||||||
txTimeout: { timeout: 70000 },
|
txTimeout: { timeout: 70000 },
|
||||||
epochTimeout: { timeout: 6000 },
|
epochTimeout: { timeout: 12000 },
|
||||||
blockConfirmations: 3,
|
blockConfirmations: 3,
|
||||||
grepTags: '@regression @smoke @slow',
|
grepTags: '@regression @smoke @slow',
|
||||||
grepFilterSpecs: true,
|
grepFilterSpecs: true,
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
export const previousEpochData = {
|
||||||
|
epoch: {
|
||||||
|
id: '7611',
|
||||||
|
validatorsConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'cd96782bc0ad5679869cf69fe7838a92212da7f53b4a214bed68067117494122',
|
||||||
|
stakedTotal: '3154229668720612941799',
|
||||||
|
rewardScore: {
|
||||||
|
rawValidatorScore: '0.2',
|
||||||
|
performanceScore: '1',
|
||||||
|
multisigScore: '0',
|
||||||
|
validatorScore: '0.2',
|
||||||
|
normalisedScore: '0.2007216887087119',
|
||||||
|
validatorStatus: 'VALIDATOR_NODE_STATUS_TENDERMINT',
|
||||||
|
__typename: 'RewardScore',
|
||||||
|
},
|
||||||
|
rankingScore: {
|
||||||
|
status: 'VALIDATOR_NODE_STATUS_TENDERMINT',
|
||||||
|
previousStatus: 'VALIDATOR_NODE_STATUS_TENDERMINT',
|
||||||
|
rankingScore: '0.211713765544955625',
|
||||||
|
stakeScore: '0.2016321576618625',
|
||||||
|
performanceScore: '1',
|
||||||
|
votingPower: '2007',
|
||||||
|
__typename: 'RankingScore',
|
||||||
|
},
|
||||||
|
__typename: 'Node',
|
||||||
|
},
|
||||||
|
__typename: 'NodeEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '887d936f797a47032eceb572a13b69b581d3b1fa595a7d021a3e3cf2a5d2acfd',
|
||||||
|
stakedTotal: '3151161904761904764551',
|
||||||
|
rewardScore: {
|
||||||
|
rawValidatorScore: '0.2',
|
||||||
|
performanceScore: '1',
|
||||||
|
multisigScore: '1',
|
||||||
|
validatorScore: '0.2',
|
||||||
|
normalisedScore: '0.2007216887087119',
|
||||||
|
validatorStatus: 'VALIDATOR_NODE_STATUS_TENDERMINT',
|
||||||
|
__typename: 'RewardScore',
|
||||||
|
},
|
||||||
|
rankingScore: {
|
||||||
|
status: 'VALIDATOR_NODE_STATUS_TENDERMINT',
|
||||||
|
previousStatus: 'VALIDATOR_NODE_STATUS_TENDERMINT',
|
||||||
|
rankingScore: '0.211507855409133255',
|
||||||
|
stakeScore: '0.2014360527706031',
|
||||||
|
performanceScore: '1',
|
||||||
|
votingPower: '2007',
|
||||||
|
__typename: 'RankingScore',
|
||||||
|
},
|
||||||
|
__typename: 'Node',
|
||||||
|
},
|
||||||
|
__typename: 'NodeEdge',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
__typename: 'NodesConnection',
|
||||||
|
},
|
||||||
|
__typename: 'Epoch',
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -14,9 +14,16 @@ import {
|
|||||||
submitUniqueRawProposal,
|
submitUniqueRawProposal,
|
||||||
voteForProposal,
|
voteForProposal,
|
||||||
} from '../../../../governance-e2e/src/support/governance.functions';
|
} from '../../../../governance-e2e/src/support/governance.functions';
|
||||||
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../../../governance-e2e/src/support/staking.functions';
|
import {
|
||||||
|
ensureSpecifiedUnstakedTokensAreAssociated,
|
||||||
|
stakingPageAssociateTokens,
|
||||||
|
stakingPageDisassociateAllTokens,
|
||||||
|
} from '../../../../governance-e2e/src/support/staking.functions';
|
||||||
import { ethereumWalletConnect } from '../../../../governance-e2e/src/support/wallet-eth.functions';
|
import { ethereumWalletConnect } from '../../../../governance-e2e/src/support/wallet-eth.functions';
|
||||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../../../governance-e2e/src/support/wallet-teardown.functions';
|
import {
|
||||||
|
switchVegaWalletPubKey,
|
||||||
|
vegaWalletSetSpecifiedApprovalAmount,
|
||||||
|
} from '../../support/wallet-functions';
|
||||||
import type { testFreeformProposal } from '../../support/common-interfaces';
|
import type { testFreeformProposal } from '../../support/common-interfaces';
|
||||||
import { formatDateWithLocalTimezone } from '@vegaprotocol/utils';
|
import { formatDateWithLocalTimezone } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
@@ -33,8 +40,9 @@ const proposalDetailsTitle = '[data-testid="proposal-title"]';
|
|||||||
const proposalDetailsDescription = '[data-testid="proposal-description"]';
|
const proposalDetailsDescription = '[data-testid="proposal-description"]';
|
||||||
const openProposals = '[data-testid="open-proposals"]';
|
const openProposals = '[data-testid="open-proposals"]';
|
||||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||||
|
const proposalDescriptionToggle = 'proposal-description-toggle';
|
||||||
const voteBreakdownToggle = 'vote-breakdown-toggle';
|
const voteBreakdownToggle = 'vote-breakdown-toggle';
|
||||||
const proposalTermsToggle = 'proposal-terms-toggle';
|
const proposalTermsToggle = 'proposal-json-toggle';
|
||||||
|
|
||||||
describe(
|
describe(
|
||||||
'Governance flow for proposal details',
|
'Governance flow for proposal details',
|
||||||
@@ -43,7 +51,7 @@ describe(
|
|||||||
before('connect wallets and set approval limit', function () {
|
before('connect wallets and set approval limit', function () {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
ethereumWalletConnect();
|
ethereumWalletConnect();
|
||||||
cy.associateTokensToVegaWallet('1');
|
// cy.associateTokensToVegaWallet('1');
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach('visit proposals tab', function () {
|
beforeEach('visit proposals tab', function () {
|
||||||
@@ -73,16 +81,28 @@ describe(
|
|||||||
'contain.text',
|
'contain.text',
|
||||||
rawProposal.rationale.title
|
rawProposal.rationale.title
|
||||||
);
|
);
|
||||||
|
cy.getByTestId(proposalDescriptionToggle).click();
|
||||||
|
cy.getByTestId('proposal-description-toggle');
|
||||||
cy.get(proposalDetailsDescription)
|
cy.get(proposalDetailsDescription)
|
||||||
.find('p')
|
.find('p')
|
||||||
.should('have.text', proposalDescription);
|
.should('have.text', proposalDescription);
|
||||||
});
|
});
|
||||||
|
// 3001-VOTE-008
|
||||||
|
getProposalInformationFromTable('ID')
|
||||||
|
.invoke('text')
|
||||||
|
.should('not.be.empty')
|
||||||
|
.and('have.length', 64);
|
||||||
|
// 3001-VOTE-009
|
||||||
|
getProposalInformationFromTable('Proposed by')
|
||||||
|
.invoke('text')
|
||||||
|
.should('not.be.empty')
|
||||||
|
.and('have.length', 64);
|
||||||
cy.getByTestId(proposalTermsToggle).click();
|
cy.getByTestId(proposalTermsToggle).click();
|
||||||
// 3001-VOTE-052
|
// 3001-VOTE-052 3001-VOTE-010
|
||||||
cy.get('code.language-json')
|
cy.get('code.language-json')
|
||||||
.should('exist')
|
.should('exist')
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get('.hljs-string').eq(0).should('have.text', '"ProposalTerms"');
|
cy.get('.hljs-attr').eq(0).should('have.text', '"id"');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -90,8 +110,6 @@ describe(
|
|||||||
it('Newly created freeform proposal details - shows proposed and closing dates', function () {
|
it('Newly created freeform proposal details - shows proposed and closing dates', function () {
|
||||||
const proposalTitle = generateFreeFormProposalTitle();
|
const proposalTitle = generateFreeFormProposalTitle();
|
||||||
const proposalTimeStamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
|
const proposalTimeStamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
|
||||||
// const currentDate = new Date(createTenDigitUnixTimeStampForSpecifiedDays(0) * 1000)
|
|
||||||
// const proposedDate = new Date(currentDate.getTime() + 60000)
|
|
||||||
|
|
||||||
submitUniqueRawProposal({
|
submitUniqueRawProposal({
|
||||||
proposalTitle: proposalTitle,
|
proposalTitle: proposalTitle,
|
||||||
@@ -109,16 +127,9 @@ describe(
|
|||||||
closingDate
|
closingDate
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
cy.wrap(
|
getProposalInformationFromTable('Proposed on')
|
||||||
formatDateWithLocalTimezone(
|
.invoke('text')
|
||||||
new Date(createTenDigitUnixTimeStampForSpecifiedDays(0) * 1000)
|
.should('not.be.empty');
|
||||||
)
|
|
||||||
).then((proposalDate) => {
|
|
||||||
getProposalInformationFromTable('Proposed on').should(
|
|
||||||
'have.text',
|
|
||||||
proposalDate
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Newly created proposal details - shows default status set to fail', function () {
|
it('Newly created proposal details - shows default status set to fail', function () {
|
||||||
@@ -293,5 +304,33 @@ describe(
|
|||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Able to vote for proposal twice by switching public key', function () {
|
||||||
|
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||||
|
createRawProposal();
|
||||||
|
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||||
|
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||||
|
cy.get(viewProposalButton).click()
|
||||||
|
);
|
||||||
|
voteForProposal('for');
|
||||||
|
cy.contains('You voted: For').should('be.visible');
|
||||||
|
ethereumWalletConnect();
|
||||||
|
switchVegaWalletPubKey();
|
||||||
|
stakingPageAssociateTokens('2');
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
|
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||||
|
cy.get(viewProposalButton).click()
|
||||||
|
);
|
||||||
|
cy.getByTestId('you-voted').should('not.exist');
|
||||||
|
voteForProposal('against');
|
||||||
|
cy.contains('You voted: Against').should('be.visible');
|
||||||
|
switchVegaWalletPubKey();
|
||||||
|
cy.get(proposalVoteProgressForTokens).should('contain.text', '1.00');
|
||||||
|
// Checking vote status for different public keys is displayed correctly
|
||||||
|
cy.contains('You voted: For').should('be.visible');
|
||||||
|
});
|
||||||
|
switchVegaWalletPubKey();
|
||||||
|
stakingPageDisassociateAllTokens();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ import {
|
|||||||
createUpdateNetworkProposalTxBody,
|
createUpdateNetworkProposalTxBody,
|
||||||
createFreeFormProposalTxBody,
|
createFreeFormProposalTxBody,
|
||||||
} from '../../support/proposal.functions';
|
} from '../../support/proposal.functions';
|
||||||
|
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
|
||||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
|
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions';
|
||||||
|
|
||||||
const proposalListItem = '[data-testid="proposals-list-item"]';
|
const proposalListItem = '[data-testid="proposals-list-item"]';
|
||||||
const closedProposals = '[data-testid="closed-proposals"]';
|
const closedProposals = '[data-testid="closed-proposals"]';
|
||||||
@@ -43,6 +44,7 @@ context(
|
|||||||
waitForSpinner();
|
waitForSpinner();
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
ethereumWalletConnect();
|
ethereumWalletConnect();
|
||||||
|
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||||
navigateTo(navigation.proposals);
|
navigateTo(navigation.proposals);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -87,8 +89,14 @@ context(
|
|||||||
});
|
});
|
||||||
cy.get(proposalStatus).should('have.text', 'Open');
|
cy.get(proposalStatus).should('have.text', 'Open');
|
||||||
voteForProposal('for');
|
voteForProposal('for');
|
||||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Passed');
|
cy.get(proposalStatus, proposalTimeout)
|
||||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Enacted');
|
.should('have.text', 'Passed')
|
||||||
|
.then(() => {
|
||||||
|
cy.get(proposalStatus, proposalTimeout).should(
|
||||||
|
'have.text',
|
||||||
|
'Enacted'
|
||||||
|
);
|
||||||
|
});
|
||||||
cy.get(votesTable).within(() => {
|
cy.get(votesTable).within(() => {
|
||||||
cy.contains('Vote passed.').should('be.visible');
|
cy.contains('Vote passed.').should('be.visible');
|
||||||
cy.contains('Voting has ended.').should('be.visible');
|
cy.contains('Voting has ended.').should('be.visible');
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
governanceProposalType,
|
governanceProposalType,
|
||||||
submitUniqueRawProposal,
|
submitUniqueRawProposal,
|
||||||
voteForProposal,
|
voteForProposal,
|
||||||
waitForProposalSubmitted,
|
|
||||||
waitForProposalSync,
|
waitForProposalSync,
|
||||||
} from '../../support/governance.functions';
|
} from '../../support/governance.functions';
|
||||||
|
|
||||||
@@ -33,7 +32,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
vegaWalletSetSpecifiedApprovalAmount,
|
vegaWalletSetSpecifiedApprovalAmount,
|
||||||
vegaWalletTeardown,
|
vegaWalletTeardown,
|
||||||
} from '../../support/wallet-teardown.functions';
|
} from '../../support/wallet-functions';
|
||||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
import type { testFreeformProposal } from '../../support/common-interfaces';
|
import type { testFreeformProposal } from '../../support/common-interfaces';
|
||||||
|
|
||||||
@@ -46,11 +45,7 @@ const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
|
|||||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||||
const rawProposalData = '[data-testid="proposal-data"]';
|
const rawProposalData = '[data-testid="proposal-data"]';
|
||||||
const minVoteButton = '[data-testid="min-vote"]';
|
|
||||||
const maxVoteButton = '[data-testid="max-vote"]';
|
|
||||||
const voteButtons = '[data-testid="vote-buttons"]';
|
const voteButtons = '[data-testid="vote-buttons"]';
|
||||||
const votingDate = '[data-testid="voting-date"]';
|
|
||||||
const voteTwoMinExtraNote = '[data-testid="voting-2-mins-extra"]';
|
|
||||||
const rejectProposalsLink = '[href="/proposals/rejected"]';
|
const rejectProposalsLink = '[href="/proposals/rejected"]';
|
||||||
const feedbackError = '[data-testid="Error"]';
|
const feedbackError = '[data-testid="Error"]';
|
||||||
const noOpenProposals = '[data-testid="no-open-proposals"]';
|
const noOpenProposals = '[data-testid="no-open-proposals"]';
|
||||||
@@ -106,8 +101,7 @@ context(
|
|||||||
.and('have.text', 'There are no enacted or rejected proposals');
|
.and('have.text', 'There are no enacted or rejected proposals');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3002-PROP-002
|
// 3002-PROP-002 3002-PROP-003 3001-VOTE-012 3007-PNE-020 3004-PMAC-004 3005-PASN-004 3008-PFRO-016 3003-PMAN-004
|
||||||
// 3002-PROP-003
|
|
||||||
it('Proposal form - shows how many vega tokens are required to make a proposal', function () {
|
it('Proposal form - shows how many vega tokens are required to make a proposal', function () {
|
||||||
// 3002-PROP-005
|
// 3002-PROP-005
|
||||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||||
@@ -116,23 +110,14 @@ context(
|
|||||||
).should('be.visible');
|
).should('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Skipping as currently unable to propose using forms other than raw
|
// 3002-PROP-011 3008-PFRO-005
|
||||||
// 3002-PROP-011
|
it('Able to submit a valid freeform proposal - with minimum required tokens associated', function () {
|
||||||
it.skip('Able to submit a valid freeform proposal - with minimum required tokens associated', function () {
|
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
verifyUnstakedBalance(1);
|
||||||
cy.get(minVoteButton).should('be.visible'); // 3002-PROP-008
|
createRawProposal();
|
||||||
cy.get(maxVoteButton).should('be.visible');
|
|
||||||
cy.get(votingDate).should('not.be.empty');
|
|
||||||
cy.get(voteTwoMinExtraNote).should(
|
|
||||||
'contain.text',
|
|
||||||
'we add 2 minutes of extra time'
|
|
||||||
);
|
|
||||||
enterUniqueFreeFormProposalBody('50', generateFreeFormProposalTitle());
|
|
||||||
// 3002-PROP-012
|
|
||||||
// 3002-PROP-016
|
|
||||||
waitForProposalSubmitted();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 3008-PFRO-002 3008-PFRO-004
|
||||||
it('Able to submit a valid freeform proposal - with minimum required tokens associated - but also staked', function () {
|
it('Able to submit a valid freeform proposal - with minimum required tokens associated - but also staked', function () {
|
||||||
ensureSpecifiedUnstakedTokensAreAssociated('2');
|
ensureSpecifiedUnstakedTokensAreAssociated('2');
|
||||||
verifyUnstakedBalance(2);
|
verifyUnstakedBalance(2);
|
||||||
@@ -145,19 +130,15 @@ context(
|
|||||||
createRawProposal();
|
createRawProposal();
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('Creating a proposal - proposal rejected - when closing time sooner than system default', function () {
|
it('Creating a proposal - proposal rejected - when closing time sooner than system default', function () {
|
||||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||||
enterUniqueFreeFormProposalBody('0.1', generateFreeFormProposalTitle());
|
enterUniqueFreeFormProposalBody('0.1', generateFreeFormProposalTitle());
|
||||||
|
|
||||||
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
|
||||||
'not.exist'
|
|
||||||
);
|
|
||||||
cy.get('input:invalid')
|
cy.get('input:invalid')
|
||||||
.invoke('prop', 'validationMessage')
|
.invoke('prop', 'validationMessage')
|
||||||
.should('equal', 'Value must be greater than or equal to 1.');
|
.should('equal', 'Value must be greater than or equal to 1.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('Creating a proposal - proposal rejected - when closing time later than system default', function () {
|
it('Creating a proposal - proposal rejected - when closing time later than system default', function () {
|
||||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||||
enterUniqueFreeFormProposalBody(
|
enterUniqueFreeFormProposalBody(
|
||||||
'100000',
|
'100000',
|
||||||
@@ -280,6 +261,20 @@ context(
|
|||||||
closeDialog();
|
closeDialog();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 3007-PNE-022 3007-PNE-023 3004-PMAC-006 3004-PMAC-007 3005-PASN-006 3005-PASN-007
|
||||||
|
// 3006-PASC-006 3006-PASC-007 3008-PFRO-018 3008-PFRO-019 3003-PMAN-006 3003-PMAN-007
|
||||||
|
it('Unable to submit proposal without valid json', function () {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
cy.get(newProposalSubmitButton).click();
|
||||||
|
cy.getByTestId('input-error-text').should('have.text', 'Required');
|
||||||
|
cy.get(rawProposalData).type('Not a valid json string');
|
||||||
|
cy.get(newProposalSubmitButton).click();
|
||||||
|
cy.getByTestId('input-error-text').should(
|
||||||
|
'have.text',
|
||||||
|
'Must be valid JSON'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// 1005-PROP-009
|
// 1005-PROP-009
|
||||||
it('Unable to vote on a freeform proposal - when some but not enough vega associated', function () {
|
it('Unable to vote on a freeform proposal - when some but not enough vega associated', function () {
|
||||||
const proposalTitle = generateFreeFormProposalTitle();
|
const proposalTitle = generateFreeFormProposalTitle();
|
||||||
|
|||||||
@@ -1,24 +1,34 @@
|
|||||||
import {
|
import {
|
||||||
closeDialog,
|
closeDialog,
|
||||||
|
dissociateFromSecondWalletKey,
|
||||||
navigateTo,
|
navigateTo,
|
||||||
navigation,
|
navigation,
|
||||||
turnTelemetryOff,
|
turnTelemetryOff,
|
||||||
waitForSpinner,
|
waitForSpinner,
|
||||||
} from '../../support/common.functions';
|
} from '../../support/common.functions';
|
||||||
|
import {
|
||||||
|
getDownloadedProposalJsonPath,
|
||||||
|
getProposalFromTitle,
|
||||||
|
submitUniqueRawProposal,
|
||||||
|
} from '../../support/governance.functions';
|
||||||
import {
|
import {
|
||||||
getProposalInformationFromTable,
|
getProposalInformationFromTable,
|
||||||
goToMakeNewProposal,
|
goToMakeNewProposal,
|
||||||
governanceProposalType,
|
governanceProposalType,
|
||||||
voteForProposal,
|
voteForProposal,
|
||||||
waitForProposalSubmitted,
|
|
||||||
} from '../../support/governance.functions';
|
} from '../../support/governance.functions';
|
||||||
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
|
import {
|
||||||
|
ensureSpecifiedUnstakedTokensAreAssociated,
|
||||||
|
stakingPageAssociateTokens,
|
||||||
|
stakingPageDisassociateAllTokens,
|
||||||
|
} from '../../support/staking.functions';
|
||||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
import {
|
import {
|
||||||
|
switchVegaWalletPubKey,
|
||||||
|
vegaWalletFaucetAssetsWithoutCheck,
|
||||||
vegaWalletSetSpecifiedApprovalAmount,
|
vegaWalletSetSpecifiedApprovalAmount,
|
||||||
vegaWalletTeardown,
|
vegaWalletTeardown,
|
||||||
} from '../../support/wallet-teardown.functions';
|
} from '../../support/wallet-functions';
|
||||||
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions';
|
|
||||||
|
|
||||||
const proposalListItem = '[data-testid="proposals-list-item"]';
|
const proposalListItem = '[data-testid="proposals-list-item"]';
|
||||||
const openProposals = '[data-testid="open-proposals"]';
|
const openProposals = '[data-testid="open-proposals"]';
|
||||||
@@ -26,15 +36,11 @@ const proposalType = '[data-testid="proposal-type"]';
|
|||||||
const proposalDetails = '[data-testid="proposal-details"]';
|
const proposalDetails = '[data-testid="proposal-details"]';
|
||||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||||
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
|
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
|
||||||
const proposalValidationDeadline =
|
|
||||||
'[data-testid="proposal-validation-deadline"]';
|
|
||||||
const proposalParameterSelect = '[data-testid="proposal-parameter-select"]';
|
const proposalParameterSelect = '[data-testid="proposal-parameter-select"]';
|
||||||
const proposalMarketSelect = '[data-testid="proposal-market-select"]';
|
const proposalMarketSelect = '[data-testid="proposal-market-select"]';
|
||||||
const newProposalTitle = '[data-testid="proposal-title"]';
|
const newProposalTitle = '[data-testid="proposal-title"]';
|
||||||
const newProposalDescription = '[data-testid="proposal-description"]';
|
const newProposalDescription = '[data-testid="proposal-description"]';
|
||||||
const newProposalTerms = '[data-testid="proposal-terms"]';
|
const newProposalTerms = '[data-testid="proposal-terms"]';
|
||||||
const currentParameterValue =
|
|
||||||
'[data-testid="selected-proposal-param-current-value"]';
|
|
||||||
const newProposedParameterValue =
|
const newProposedParameterValue =
|
||||||
'[data-testid="selected-proposal-param-new-value"]';
|
'[data-testid="selected-proposal-param-new-value"]';
|
||||||
const minVoteDeadline = '[data-testid="min-vote"]';
|
const minVoteDeadline = '[data-testid="min-vote"]';
|
||||||
@@ -50,15 +56,15 @@ const feedbackError = '[data-testid="Error"]';
|
|||||||
const viewProposalBtn = 'view-proposal-btn';
|
const viewProposalBtn = 'view-proposal-btn';
|
||||||
const liquidityVoteStatus = 'liquidity-votes-status';
|
const liquidityVoteStatus = 'liquidity-votes-status';
|
||||||
const tokenVoteStatus = 'token-votes-status';
|
const tokenVoteStatus = 'token-votes-status';
|
||||||
const proposalTermsSection = 'proposal';
|
const proposalJsonToggle = 'proposal-json-toggle';
|
||||||
|
const proposalJsonSection = 'proposal-json';
|
||||||
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
|
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
|
||||||
const fUSDCId =
|
const fUSDCId =
|
||||||
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc';
|
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc';
|
||||||
const epochTimeout = Cypress.env('epochTimeout');
|
|
||||||
const proposalTimeout = { timeout: 14000 };
|
const proposalTimeout = { timeout: 14000 };
|
||||||
|
|
||||||
// 3001-VOTE-007
|
// 3001-VOTE-007
|
||||||
context.skip(
|
context(
|
||||||
'Governance flow - form validations for different governance proposals',
|
'Governance flow - form validations for different governance proposals',
|
||||||
{ tags: '@slow' },
|
{ tags: '@slow' },
|
||||||
function () {
|
function () {
|
||||||
@@ -79,28 +85,10 @@ context.skip(
|
|||||||
navigateTo(navigation.proposals);
|
navigateTo(navigation.proposals);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to submit valid update network parameter proposal', function () {
|
|
||||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
|
||||||
// 3002-PROP-006
|
|
||||||
cy.get(newProposalTitle).type('Test update network parameter proposal');
|
|
||||||
// 3002-PROP-007
|
|
||||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
|
||||||
|
|
||||||
cy.get(proposalParameterSelect).find('option').should('have.length', 117);
|
|
||||||
cy.get(proposalParameterSelect).select(
|
|
||||||
// 3007-PNEC-002
|
|
||||||
'governance_proposal_asset_minEnact'
|
|
||||||
);
|
|
||||||
cy.get(currentParameterValue).should('have.value', '2s');
|
|
||||||
cy.get(newProposedParameterValue).type('5s'); // 3007-PNEC-003
|
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
|
||||||
waitForProposalSubmitted();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Unable to submit network parameter with missing/invalid fields', function () {
|
it('Unable to submit network parameter with missing/invalid fields', function () {
|
||||||
navigateTo(navigation.proposals);
|
navigateTo(navigation.proposals);
|
||||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(proposalDownloadBtn).click();
|
||||||
cy.get(inputError).should('have.length', 3);
|
cy.get(inputError).should('have.length', 3);
|
||||||
cy.get(newProposalTitle).type(
|
cy.get(newProposalTitle).type(
|
||||||
'Invalid update network parameter proposal'
|
'Invalid update network parameter proposal'
|
||||||
@@ -111,62 +99,78 @@ context.skip(
|
|||||||
);
|
);
|
||||||
cy.get(newProposedParameterValue).type('0');
|
cy.get(newProposedParameterValue).type('0');
|
||||||
cy.get(proposalVoteDeadline).clear().type('0');
|
cy.get(proposalVoteDeadline).clear().type('0');
|
||||||
cy.get(newProposalSubmitButton).click();
|
|
||||||
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
|
||||||
'not.exist'
|
|
||||||
);
|
|
||||||
cy.get(proposalVoteDeadline).clear().type('9000');
|
|
||||||
cy.get(newProposalSubmitButton).click();
|
|
||||||
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
|
||||||
'not.exist'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Able to download network param proposal json', function () {
|
|
||||||
const downloadFolder = './cypress/downloads/';
|
|
||||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
|
||||||
cy.log('Download proposal file');
|
|
||||||
cy.get(proposalDownloadBtn)
|
cy.get(proposalDownloadBtn)
|
||||||
.should('be.visible')
|
|
||||||
.click()
|
.click()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const filename =
|
cy.wrap(
|
||||||
downloadFolder +
|
getDownloadedProposalJsonPath('vega-network-param-proposal-')
|
||||||
'vega-network-param-proposal-' +
|
).then((filePath) => {
|
||||||
getFormattedTime() +
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
'.json';
|
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||||
cy.readFile(filename, proposalTimeout)
|
});
|
||||||
.its('terms.updateNetworkParameter')
|
|
||||||
.should('exist');
|
|
||||||
});
|
});
|
||||||
|
cy.get(newProposalSubmitButton).click();
|
||||||
|
validateDialogContentMsg('PROPOSAL_ERROR_CLOSE_TIME_TOO_SOON');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3007-PNEC-001 3007-PNEC-003
|
||||||
|
it('Able to download and submit network param proposal', function () {
|
||||||
|
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||||
|
// 3007-PNEC-006
|
||||||
|
cy.get(newProposalTitle)
|
||||||
|
.siblings()
|
||||||
|
.should('contain.text', '(100 characters or less)');
|
||||||
|
// 3007-PNEC-004 3007-PNEC-005
|
||||||
|
cy.get(newProposalTitle).type('Test update network parameter proposal');
|
||||||
|
// 3007-PNEC-009
|
||||||
|
cy.get(newProposalDescription)
|
||||||
|
.siblings()
|
||||||
|
.should('contain.text', '(20,000 characters or less)');
|
||||||
|
// 3007-PNEC-007 3007-PNEC-008
|
||||||
cy.get(newProposalDescription).type('E2E test for downloading proposals');
|
cy.get(newProposalDescription).type('E2E test for downloading proposals');
|
||||||
|
// 3007-PNEC-010
|
||||||
cy.get(proposalParameterSelect).select(
|
cy.get(proposalParameterSelect).select(
|
||||||
'governance_proposal_asset_minClose'
|
'governance_proposal_asset_minClose'
|
||||||
);
|
);
|
||||||
|
// 3007-PNEC-011
|
||||||
cy.get(newProposedParameterValue).type('10s');
|
cy.get(newProposedParameterValue).type('10s');
|
||||||
|
// 3007-PNEC-012
|
||||||
|
cy.get(proposalVoteDeadline).clear().type('2');
|
||||||
|
// 3007-PNEC-013 3007-PNEC-014
|
||||||
|
cy.getByTestId('voting-date').invoke('text').should('not.be.empty');
|
||||||
|
// 3007-PNEC-015
|
||||||
|
cy.get(maxEnactDeadline).click();
|
||||||
|
// 3007-PNEC-016
|
||||||
|
cy.getByTestId('enactment-date').invoke('text').should('not.be.empty');
|
||||||
|
// 3007-PNEC-017
|
||||||
|
cy.contains(
|
||||||
|
'Time till enactment (must be equal to or after vote close)'
|
||||||
|
).should('be.visible');
|
||||||
|
// 3007-PNE-018
|
||||||
cy.log('Download updated proposal file');
|
cy.log('Download updated proposal file');
|
||||||
cy.get(proposalDownloadBtn)
|
cy.get(proposalDownloadBtn)
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.click()
|
.click()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const filename =
|
cy.wrap(
|
||||||
downloadFolder +
|
getDownloadedProposalJsonPath('vega-network-param-proposal-')
|
||||||
'vega-network-param-proposal-' +
|
).then((filePath) => {
|
||||||
getFormattedTime() +
|
cy.readFile(String(filePath), { timeout: 14000 }).then(
|
||||||
'.json';
|
(jsonFile) => {
|
||||||
cy.get(proposalDownloadBtn).should('be.visible').click();
|
cy.wrap(jsonFile)
|
||||||
cy.readFile(filename, proposalTimeout).then((jsonFile) => {
|
.its('rationale.description')
|
||||||
cy.wrap(jsonFile)
|
.should('eq', 'E2E test for downloading proposals');
|
||||||
.its('rationale.description')
|
cy.wrap(jsonFile)
|
||||||
.should('eq', 'E2E test for downloading proposals');
|
.its('terms.updateNetworkParameter.changes.key')
|
||||||
cy.wrap(jsonFile)
|
.should('eq', 'governance.proposal.asset.minClose');
|
||||||
.its('terms.updateNetworkParameter.changes.key')
|
cy.wrap(jsonFile)
|
||||||
.should('eq', 'governance.proposal.asset.minClose');
|
.its('terms.updateNetworkParameter.changes.value')
|
||||||
cy.wrap(jsonFile)
|
.should('eq', '10s');
|
||||||
.its('terms.updateNetworkParameter.changes.value')
|
}
|
||||||
.should('eq', '10s');
|
);
|
||||||
|
// 3007-PNE-019
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -184,40 +188,78 @@ context.skip(
|
|||||||
cy.get(maxVoteDeadline).click();
|
cy.get(maxVoteDeadline).click();
|
||||||
cy.get(enactmentDeadlineError).should(
|
cy.get(enactmentDeadlineError).should(
|
||||||
'have.text',
|
'have.text',
|
||||||
'Proposal will fail if enactment is earlier than the voting deadline'
|
'The proposal will fail if enactment is earlier than the voting deadline'
|
||||||
);
|
);
|
||||||
|
cy.get(proposalDownloadBtn)
|
||||||
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
cy.wrap(
|
||||||
|
getDownloadedProposalJsonPath('vega-network-param-proposal-')
|
||||||
|
).then((filePath) => {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||||
|
});
|
||||||
|
});
|
||||||
cy.get(newProposalSubmitButton).click();
|
cy.get(newProposalSubmitButton).click();
|
||||||
cy.get(feedbackError).should(
|
validateFeedBackMsg(
|
||||||
'have.text',
|
|
||||||
'Invalid params: proposal_submission.terms.closing_timestamp (cannot be after enactment time)'
|
'Invalid params: proposal_submission.terms.closing_timestamp (cannot be after enactment time)'
|
||||||
);
|
);
|
||||||
closeDialog();
|
|
||||||
cy.get(minVoteDeadline).click();
|
|
||||||
cy.get(enactmentDeadlineError).should('not.exist');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3003-PMAN-001
|
// 3003-PMAN-001
|
||||||
it('Able to submit valid new market proposal', function () {
|
it(
|
||||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
'Able to submit valid new market proposal',
|
||||||
cy.get(newProposalTitle).type('Test new market proposal');
|
{ tags: '@smoke' },
|
||||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
function () {
|
||||||
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
const proposalTitle = 'Test new market proposal';
|
||||||
const newMarketPayload = JSON.stringify(newMarketProposal);
|
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||||
cy.get(newProposalTerms).type(newMarketPayload, {
|
cy.get(newProposalTitle).type('Test new market proposal');
|
||||||
parseSpecialCharSequences: false,
|
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||||
delay: 2,
|
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
||||||
|
const newMarketPayload = JSON.stringify(newMarketProposal);
|
||||||
|
cy.get(newProposalTerms).type(newMarketPayload, {
|
||||||
|
parseSpecialCharSequences: false,
|
||||||
|
delay: 2,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
cy.get(proposalDownloadBtn)
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
.should('be.visible')
|
||||||
waitForProposalSubmitted();
|
.click()
|
||||||
});
|
.then(() => {
|
||||||
|
cy.wrap(
|
||||||
|
getDownloadedProposalJsonPath('vega-new-market-proposal-')
|
||||||
|
).then((filePath) => {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath }); // 3003-PMAN-003
|
||||||
|
});
|
||||||
|
});
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
|
getProposalFromTitle(proposalTitle).within(() =>
|
||||||
|
cy.getByTestId('view-proposal-btn').click()
|
||||||
|
);
|
||||||
|
cy.getByTestId('proposal-market-data').within(() => {
|
||||||
|
cy.getByTestId('proposal-market-data-toggle').click();
|
||||||
|
cy.contains('Key details').click();
|
||||||
|
getMarketProposalDetailsFromTable('Name').should(
|
||||||
|
'have.text',
|
||||||
|
'Token test market'
|
||||||
|
);
|
||||||
|
cy.contains('Settlement asset').click();
|
||||||
|
// Settlement asset symbol
|
||||||
|
cy.getByTestId('3_value').should('have.text', 'fBTC');
|
||||||
|
cy.contains('Oracle').click();
|
||||||
|
cy.getByTestId('oracle-spec-links').should('have.attr', 'href');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
it('Unable to submit new market proposal with missing/invalid fields', function () {
|
it('Unable to submit new market proposal with missing/invalid fields', function () {
|
||||||
const errorMsg =
|
const errorMsg =
|
||||||
'Invalid params: the transaction does not use a valid Vega command: unknown field "invalid" in vega.NewMarket';
|
'Invalid params: the transaction does not use a valid Vega command: unknown field "invalid" in vega.NewMarket';
|
||||||
|
|
||||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(proposalDownloadBtn).should('be.visible').click();
|
||||||
cy.get(inputError).should('have.length', 3);
|
cy.get(inputError).should('have.length', 3);
|
||||||
cy.get(newProposalTitle).type('Test new market proposal');
|
cy.get(newProposalTitle).type('Test new market proposal');
|
||||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||||
@@ -229,14 +271,27 @@ context.skip(
|
|||||||
delay: 2,
|
delay: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
cy.get(proposalDownloadBtn)
|
||||||
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
cy.wrap(
|
||||||
|
getDownloadedProposalJsonPath('vega-new-market-proposal-')
|
||||||
|
).then((filePath) => {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||||
|
});
|
||||||
|
});
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||||
cy.get(feedbackError).should('have.text', errorMsg);
|
validateFeedBackMsg(errorMsg);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Will fail if run after 'Able to submit update market proposal and vote for proposal'
|
// Will fail if run after 'Able to submit update market proposal and vote for proposal'
|
||||||
// 3002-PROP-022
|
// 3002-PROP-022
|
||||||
it('Unable to submit update market proposal without equity-like share in the market', function () {
|
it('Unable to submit update market proposal without equity-like share in the market', function () {
|
||||||
|
switchVegaWalletPubKey();
|
||||||
|
stakingPageAssociateTokens('1');
|
||||||
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||||
cy.get(newProposalTitle).type('Test update market proposal - rejected');
|
cy.get(newProposalTitle).type('Test update market proposal - rejected');
|
||||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||||
@@ -248,12 +303,24 @@ context.skip(
|
|||||||
delay: 2,
|
delay: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
cy.get(proposalDownloadBtn)
|
||||||
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
cy.wrap(
|
||||||
|
getDownloadedProposalJsonPath('vega-update-market-proposal-')
|
||||||
|
).then((filePath) => {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||||
|
});
|
||||||
|
});
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
||||||
cy.getByTestId('dialog-content')
|
validateDialogContentMsg('PROPOSAL_ERROR_INSUFFICIENT_EQUITY_LIKE_SHARE');
|
||||||
.find('p')
|
closeDialog();
|
||||||
.should('have.text', 'PROPOSAL_ERROR_INSUFFICIENT_EQUITY_LIKE_SHARE');
|
ethereumWalletConnect();
|
||||||
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
stakingPageDisassociateAllTokens();
|
||||||
|
switchVegaWalletPubKey();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3002-PROP-020
|
// 3002-PROP-020
|
||||||
@@ -275,15 +342,25 @@ context.skip(
|
|||||||
delay: 2,
|
delay: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
cy.get(proposalDownloadBtn)
|
||||||
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
cy.wrap(
|
||||||
|
getDownloadedProposalJsonPath('vega-update-market-proposal-')
|
||||||
|
).then((filePath) => {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||||
|
});
|
||||||
|
});
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||||
cy.get(feedbackError).should(
|
validateFeedBackMsg(
|
||||||
'have.text',
|
|
||||||
'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)'
|
'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3001-VOTE-092 3004-PMAC-001
|
// 3001-VOTE-092 3004-PMAC-001 3004-PMAC-003
|
||||||
it('Able to submit update market proposal and vote for proposal', function () {
|
it('Able to submit update market proposal and vote for proposal', function () {
|
||||||
vegaWalletFaucetAssetsWithoutCheck(
|
vegaWalletFaucetAssetsWithoutCheck(
|
||||||
fUSDCId,
|
fUSDCId,
|
||||||
@@ -313,11 +390,20 @@ context.skip(
|
|||||||
delay: 2,
|
delay: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(proposalDownloadBtn)
|
||||||
waitForProposalSubmitted();
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
cy.wrap(
|
||||||
|
getDownloadedProposalJsonPath('vega-update-market-proposal-')
|
||||||
|
).then((filePath) => {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath });
|
||||||
|
});
|
||||||
|
});
|
||||||
navigateTo(navigation.proposals);
|
navigateTo(navigation.proposals);
|
||||||
cy.get('@EnactedMarketId').then((marketId) => {
|
cy.get('@EnactedMarketId').then((marketId) => {
|
||||||
cy.contains(String(marketId))
|
cy.contains(String(marketId).slice(0, 6))
|
||||||
.parentsUntil(proposalListItem)
|
.parentsUntil(proposalListItem)
|
||||||
.last()
|
.last()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
@@ -341,12 +427,13 @@ context.skip(
|
|||||||
'contain.text',
|
'contain.text',
|
||||||
'Currently expected to pass'
|
'Currently expected to pass'
|
||||||
);
|
);
|
||||||
|
cy.getByTestId('vote-breakdown-toggle').click();
|
||||||
getProposalInformationFromTable('Expected to pass')
|
getProposalInformationFromTable('Expected to pass')
|
||||||
.contains('👍 by token vote')
|
.contains('👍 by token vote')
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3001-VOTE-026 3001-VOTE-027 3001-VOTE-028 3001-VOTE-095 3001-VOTE-096 3005-PASN-001
|
// 3001-VOTE-026 3001-VOTE-027 3001-VOTE-028 3001-VOTE-095 3001-VOTE-096 3005-PASN-001
|
||||||
it('Able to submit new asset proposal using min deadlines', function () {
|
it('Able to submit new asset proposal using min deadlines', function () {
|
||||||
const proposalTitle = 'Test new asset proposal';
|
const proposalTitle = 'Test new asset proposal';
|
||||||
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||||
@@ -362,25 +449,23 @@ context.skip(
|
|||||||
cy.get(minVoteDeadline).click();
|
cy.get(minVoteDeadline).click();
|
||||||
cy.get(minValidationDeadline).click();
|
cy.get(minValidationDeadline).click();
|
||||||
cy.get(minEnactDeadline).click();
|
cy.get(minEnactDeadline).click();
|
||||||
|
cy.get(proposalDownloadBtn)
|
||||||
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
cy.wrap(
|
||||||
|
getDownloadedProposalJsonPath('vega-new-asset-proposal-')
|
||||||
|
).then((filePath) => {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath, submit: false }); // 3005-PASN-003
|
||||||
|
});
|
||||||
|
});
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
|
||||||
'be.visible'
|
|
||||||
);
|
|
||||||
cy.contains('Proposal waiting for node vote', proposalTimeout).should(
|
|
||||||
'be.visible'
|
|
||||||
);
|
|
||||||
closeDialog();
|
closeDialog();
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
// cannot submit a proposal with ERC20 address already in use
|
// cannot submit a proposal with ERC20 address already in use
|
||||||
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
||||||
cy.getByTestId('dialog-content')
|
validateDialogContentMsg('PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE');
|
||||||
.last()
|
|
||||||
.within(() => {
|
|
||||||
cy.get('p').should(
|
|
||||||
'have.text',
|
|
||||||
'PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
closeDialog();
|
closeDialog();
|
||||||
navigateTo(navigation.proposals);
|
navigateTo(navigation.proposals);
|
||||||
cy.contains(proposalTitle)
|
cy.contains(proposalTitle)
|
||||||
@@ -389,7 +474,8 @@ context.skip(
|
|||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId(viewProposalBtn).click();
|
cy.getByTestId(viewProposalBtn).click();
|
||||||
});
|
});
|
||||||
cy.getByTestId(proposalTermsSection).within(() => {
|
cy.getByTestId(proposalJsonToggle).click();
|
||||||
|
cy.getByTestId(proposalJsonSection).within(() => {
|
||||||
cy.contains('USDT Coin').should('be.visible');
|
cy.contains('USDT Coin').should('be.visible');
|
||||||
cy.contains('USDT').should('be.visible');
|
cy.contains('USDT').should('be.visible');
|
||||||
});
|
});
|
||||||
@@ -397,15 +483,8 @@ context.skip(
|
|||||||
|
|
||||||
it('Unable to submit new asset proposal with missing/invalid fields', function () {
|
it('Unable to submit new asset proposal with missing/invalid fields', function () {
|
||||||
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(proposalDownloadBtn).should('be.visible').click();
|
||||||
cy.get(inputError).should('have.length', 3);
|
cy.get(inputError).should('have.length', 3);
|
||||||
cy.get(newProposalTitle).type('Invalid new asset proposal');
|
|
||||||
cy.get(newProposalDescription).type('Invalid E2E test for proposals');
|
|
||||||
cy.get(proposalValidationDeadline).clear().type('2');
|
|
||||||
cy.get(newProposalSubmitButton).click();
|
|
||||||
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
|
||||||
'not.exist'
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to submit update asset proposal using min deadline', function () {
|
it('Able to submit update asset proposal using min deadline', function () {
|
||||||
@@ -416,8 +495,17 @@ context.skip(
|
|||||||
enterUpdateAssetProposalDetails();
|
enterUpdateAssetProposalDetails();
|
||||||
cy.get(minVoteDeadline).click();
|
cy.get(minVoteDeadline).click();
|
||||||
cy.get(minEnactDeadline).click();
|
cy.get(minEnactDeadline).click();
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(proposalDownloadBtn)
|
||||||
waitForProposalSubmitted();
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
cy.wrap(
|
||||||
|
getDownloadedProposalJsonPath('vega-update-asset-proposal-')
|
||||||
|
).then((filePath) => {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath });
|
||||||
|
});
|
||||||
|
});
|
||||||
navigateTo(navigation.proposals);
|
navigateTo(navigation.proposals);
|
||||||
cy.get(openProposals).within(() => {
|
cy.get(openProposals).within(() => {
|
||||||
cy.get(proposalType)
|
cy.get(proposalType)
|
||||||
@@ -425,7 +513,7 @@ context.skip(
|
|||||||
.parentsUntil(proposalListItem)
|
.parentsUntil(proposalListItem)
|
||||||
.last()
|
.last()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get(proposalDetails).should('contain.text', assetId); // 3001-VOTE-029
|
cy.get(proposalDetails).should('contain.text', assetId.slice(0, 6)); // 3001-VOTE-029
|
||||||
cy.getByTestId(viewProposalBtn).click();
|
cy.getByTestId(viewProposalBtn).click();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -433,37 +521,95 @@ context.skip(
|
|||||||
.invoke('text')
|
.invoke('text')
|
||||||
.should('not.be.empty');
|
.should('not.be.empty');
|
||||||
// 3001-VOTE-030 3001-VOTE-031
|
// 3001-VOTE-030 3001-VOTE-031
|
||||||
cy.getByTestId(proposalTermsSection).within(() => {
|
cy.getByTestId(proposalJsonToggle).click();
|
||||||
cy.contains('UpdateAsset').should('be.visible');
|
cy.getByTestId(proposalJsonSection).within(() => {
|
||||||
cy.contains('UpdateERC20').should('be.visible');
|
cy.contains(assetId).should('be.visible');
|
||||||
cy.contains('"lifetimeLimit": "10"').should('be.visible');
|
cy.contains('lifetimeLimit').should('be.visible');
|
||||||
|
cy.contains('10').should('be.visible');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 3006-PASC-001 3006-PASC-003
|
||||||
it('Able to submit update asset proposal using max deadline', function () {
|
it('Able to submit update asset proposal using max deadline', function () {
|
||||||
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||||
enterUpdateAssetProposalDetails();
|
enterUpdateAssetProposalDetails();
|
||||||
cy.get(maxVoteDeadline).click();
|
cy.get(maxVoteDeadline).click();
|
||||||
cy.get(maxEnactDeadline).click();
|
cy.get(maxEnactDeadline).click();
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(proposalDownloadBtn)
|
||||||
waitForProposalSubmitted();
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
cy.wrap(
|
||||||
|
getDownloadedProposalJsonPath('vega-update-asset-proposal-')
|
||||||
|
).then((filePath) => {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath });
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Unable to submit edit asset proposal with missing/invalid fields', function () {
|
it('Unable to submit edit asset proposal with missing/invalid fields', function () {
|
||||||
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(proposalDownloadBtn).should('be.visible').click();
|
||||||
cy.get(inputError).should('have.length', 3);
|
cy.get(inputError).should('have.length', 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
function getFormattedTime() {
|
it('Able to download and submit freeform proposal', function () {
|
||||||
const now = new Date();
|
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||||
const day = now.getDate().toString().padStart(2, '0');
|
// 3008-PFRO-006
|
||||||
const month = now.toLocaleString('en-US', { month: 'short' });
|
cy.get(newProposalTitle)
|
||||||
const year = now.getFullYear().toString();
|
.siblings()
|
||||||
const hours = now.getHours().toString().padStart(2, '0');
|
.should('contain.text', '(100 characters or less)'); // 3008-PFRO-007
|
||||||
const minutes = now.getMinutes().toString().padStart(2, '0');
|
// 3008-PFRO-005
|
||||||
|
cy.get(newProposalTitle).type('Test freeform proposal form');
|
||||||
|
// 3008-PFRO-009
|
||||||
|
cy.get(newProposalDescription)
|
||||||
|
.siblings()
|
||||||
|
.should('contain.text', '(20,000 characters or less)'); // 3008-PFRO-010
|
||||||
|
// 3008-PFRO-008 3002-PROP-012 3002-PROP-016
|
||||||
|
cy.get(newProposalDescription).type(
|
||||||
|
'E2E test for downloading freeform proposal'
|
||||||
|
);
|
||||||
|
// 3008-PFRO-012
|
||||||
|
cy.get(minVoteDeadline).should('exist'); // 3002-PROP-008
|
||||||
|
cy.get(maxVoteDeadline).should('exist');
|
||||||
|
// 3008-PFRO-011
|
||||||
|
cy.get(proposalVoteDeadline).clear().type('2');
|
||||||
|
// 3008-PFRO-013 3008-PFRO-014
|
||||||
|
cy.getByTestId('voting-date').invoke('text').should('not.be.empty');
|
||||||
|
// 3008-PFRO-015
|
||||||
|
cy.log('Download updated proposal file');
|
||||||
|
cy.get(proposalDownloadBtn)
|
||||||
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
cy.wrap(
|
||||||
|
getDownloadedProposalJsonPath('vega-freeform-proposal-')
|
||||||
|
).then((filePath) => {
|
||||||
|
// 3008-PFRO-019
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return `${day}-${month}-${year}-${hours}-${minutes}`;
|
after('Disassociate from second wallet key if present', function () {
|
||||||
|
cy.reload();
|
||||||
|
waitForSpinner();
|
||||||
|
ethereumWalletConnect();
|
||||||
|
dissociateFromSecondWalletKey();
|
||||||
|
});
|
||||||
|
|
||||||
|
function validateDialogContentMsg(expectedMsg: string) {
|
||||||
|
cy.getByTestId('dialog-content')
|
||||||
|
.last()
|
||||||
|
.within(() => {
|
||||||
|
cy.get('p').should('have.text', expectedMsg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateFeedBackMsg(expectedMsg: string) {
|
||||||
|
cy.get(feedbackError).should('have.text', expectedMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
function enterUpdateAssetProposalDetails() {
|
function enterUpdateAssetProposalDetails() {
|
||||||
@@ -477,5 +623,13 @@ context.skip(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMarketProposalDetailsFromTable(heading: string) {
|
||||||
|
return cy
|
||||||
|
.getByTestId('key-value-table-row')
|
||||||
|
.contains(heading)
|
||||||
|
.parent()
|
||||||
|
.siblings();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {
|
|||||||
} from '../../support/governance.functions';
|
} from '../../support/governance.functions';
|
||||||
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
|
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
|
||||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
|
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions';
|
||||||
|
|
||||||
const proposalListItem = 'proposals-list-item';
|
const proposalListItem = 'proposals-list-item';
|
||||||
const openProposals = '[data-testid="open-proposals"]';
|
const openProposals = '[data-testid="open-proposals"]';
|
||||||
@@ -86,11 +86,12 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Newly created proposals list - shows title and portion of summary', function () {
|
it('Newly created proposals list - shows title and portion of summary', function () {
|
||||||
const proposalPath = '/proposals/new-market-raw.json';
|
const proposalPath = 'src/fixtures/proposals/new-market-raw.json';
|
||||||
const enactmentTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
|
const proposalTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
|
||||||
submitUniqueRawProposal({
|
submitUniqueRawProposal({
|
||||||
proposalBody: proposalPath,
|
proposalBody: proposalPath,
|
||||||
enactmentTimestamp: enactmentTimestamp,
|
enactmentTimestamp: proposalTimestamp,
|
||||||
|
closingTimestamp: proposalTimestamp,
|
||||||
}); // 3001-VOTE-052
|
}); // 3001-VOTE-052
|
||||||
// 3001-VOTE-008
|
// 3001-VOTE-008
|
||||||
// 3001-VOTE-034
|
// 3001-VOTE-034
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
clickOnValidatorFromList,
|
clickOnValidatorFromList,
|
||||||
closeStakingDialog,
|
closeStakingDialog,
|
||||||
stakingPageAssociateTokens,
|
|
||||||
stakingValidatorPageAddStake,
|
stakingValidatorPageAddStake,
|
||||||
waitForBeginningOfEpoch,
|
waitForBeginningOfEpoch,
|
||||||
} from '../../support/staking.functions';
|
} from '../../support/staking.functions';
|
||||||
@@ -15,7 +14,7 @@ import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
|||||||
import {
|
import {
|
||||||
depositAsset,
|
depositAsset,
|
||||||
vegaWalletTeardown,
|
vegaWalletTeardown,
|
||||||
} from '../../support/wallet-teardown.functions';
|
} from '../../support/wallet-functions';
|
||||||
|
|
||||||
const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de';
|
const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de';
|
||||||
const vegaWalletUnstakedBalance =
|
const vegaWalletUnstakedBalance =
|
||||||
@@ -30,20 +29,22 @@ context('rewards - flow', { tags: '@slow' }, function () {
|
|||||||
turnTelemetryOff();
|
turnTelemetryOff();
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
waitForSpinner();
|
waitForSpinner();
|
||||||
depositAsset(vegaAssetAddress, '1000', 18);
|
|
||||||
cy.validatorsSelfDelegate();
|
|
||||||
ethereumWalletConnect();
|
ethereumWalletConnect();
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.VegaWalletTopUpRewardsPool(30, 200);
|
depositAsset(vegaAssetAddress, '1000', 18);
|
||||||
navigateTo(navigation.validators);
|
cy.getByTestId('currency-title', txTimeout).should(
|
||||||
|
'contain.text',
|
||||||
|
'Collateral'
|
||||||
|
);
|
||||||
vegaWalletTeardown();
|
vegaWalletTeardown();
|
||||||
stakingPageAssociateTokens('6000');
|
cy.associateTokensToVegaWallet('6000');
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
cy.VegaWalletTopUpRewardsPool();
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||||
'contain',
|
'contain',
|
||||||
'6,000.0',
|
'6,000.0',
|
||||||
txTimeout
|
txTimeout
|
||||||
);
|
);
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
clickOnValidatorFromList(0);
|
clickOnValidatorFromList(0);
|
||||||
stakingValidatorPageAddStake('3000');
|
stakingValidatorPageAddStake('3000');
|
||||||
closeStakingDialog();
|
closeStakingDialog();
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
|||||||
import {
|
import {
|
||||||
vegaWalletSetSpecifiedApprovalAmount,
|
vegaWalletSetSpecifiedApprovalAmount,
|
||||||
vegaWalletTeardown,
|
vegaWalletTeardown,
|
||||||
} from '../../support/wallet-teardown.functions';
|
} from '../../support/wallet-functions';
|
||||||
const stakeValidatorListTotalStake = 'total-stake';
|
const stakeValidatorListTotalStake = 'total-stake';
|
||||||
const stakeValidatorListTotalShare = 'total-stake-share';
|
const stakeValidatorListTotalShare = 'total-stake-share';
|
||||||
const stakeValidatorListStakePercentage = 'stake-percentage';
|
const stakeValidatorListStakePercentage = 'stake-percentage';
|
||||||
@@ -54,12 +54,10 @@ context(
|
|||||||
'Staking Tab - with eth and vega wallets connected',
|
'Staking Tab - with eth and vega wallets connected',
|
||||||
{ tags: '@slow' },
|
{ tags: '@slow' },
|
||||||
function () {
|
function () {
|
||||||
// 2001-STKE-002, 2001-STKE-032
|
// 1002-STKE-002, 1002-STKE-032
|
||||||
before('visit staking tab and connect vega wallet', function () {
|
before('visit staking tab and connect vega wallet', function () {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
ethereumWalletConnect();
|
ethereumWalletConnect();
|
||||||
// this is a workaround for #2422 which can be removed once issue is resolved
|
|
||||||
cy.associateTokensToVegaWallet('4');
|
|
||||||
vegaWalletSetSpecifiedApprovalAmount('1000');
|
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -77,25 +75,41 @@ context(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 1002-STKE-035 1002-STKE-036
|
||||||
|
it('Unable to stake against a validator with less than minimum and more than associated amount', function () {
|
||||||
|
ensureSpecifiedUnstakedTokensAreAssociated('3');
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
verifyEthWalletTotalAssociatedBalance('3.0');
|
||||||
|
verifyEthWalletAssociatedBalance('3.0');
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
cy.getByTestId(stakeAddStakeRadioButton, epochTimeout).click({
|
||||||
|
force: true,
|
||||||
|
});
|
||||||
|
cy.getByTestId(stakeTokenAmountInputBox).type('0.001');
|
||||||
|
cy.getByTestId(stakeTokenSubmitButton).should('be.disabled');
|
||||||
|
cy.getByTestId(stakeTokenAmountInputBox).clear().type('4');
|
||||||
|
cy.getByTestId(stakeTokenSubmitButton).should('be.disabled');
|
||||||
|
});
|
||||||
it('Able to stake against a validator - using vega from wallet', function () {
|
it('Able to stake against a validator - using vega from wallet', function () {
|
||||||
ensureSpecifiedUnstakedTokensAreAssociated('3');
|
ensureSpecifiedUnstakedTokensAreAssociated('3');
|
||||||
verifyUnstakedBalance(3.0);
|
verifyUnstakedBalance(3.0);
|
||||||
verifyEthWalletTotalAssociatedBalance('3.0');
|
verifyEthWalletTotalAssociatedBalance('3.0');
|
||||||
verifyEthWalletAssociatedBalance('3.0');
|
verifyEthWalletAssociatedBalance('3.0');
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
// 2001-STKE-031
|
// 1002-STKE-031
|
||||||
clickOnValidatorFromList(0);
|
clickOnValidatorFromList(0);
|
||||||
// 2001-STKE-033, 2001-STKE-034, 2001-STKE-037
|
// 1002-STKE-033, 1002-STKE-034, 1002-STKE-037
|
||||||
stakingValidatorPageAddStake('2');
|
stakingValidatorPageAddStake('2');
|
||||||
verifyUnstakedBalance(1.0);
|
verifyUnstakedBalance(1.0);
|
||||||
// 2001-STKE-039
|
// 1002-STKE-039
|
||||||
verifyStakedBalance(2.0);
|
verifyStakedBalance(2.0);
|
||||||
verifyNextEpochValue(2.0); // 2001-STKE-016 2001-STKE-038
|
verifyNextEpochValue(2.0); // 1002-STKE-016 1002-STKE-038
|
||||||
verifyThisEpochValue(2.0); // 2001-STKE-013
|
verifyThisEpochValue(2.0); // 1002-STKE-013
|
||||||
closeStakingDialog();
|
closeStakingDialog();
|
||||||
navigateTo(navigation.validators);
|
navigateTo(navigation.validators);
|
||||||
|
|
||||||
// 2002-SINC-007
|
// 2002-SINC-007 1002-STKE-015 1002-STKE-017 1002-STKE-052
|
||||||
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%');
|
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -109,6 +123,7 @@ context(
|
|||||||
cy.getByTestId(userStake, epochTimeout)
|
cy.getByTestId(userStake, epochTimeout)
|
||||||
.first()
|
.first()
|
||||||
.should('have.text', '2.00');
|
.should('have.text', '2.00');
|
||||||
|
waitForBeginningOfEpoch();
|
||||||
cy.getByTestId('total-stake').first().realHover();
|
cy.getByTestId('total-stake').first().realHover();
|
||||||
cy.getByTestId('staked-by-user-tooltip')
|
cy.getByTestId('staked-by-user-tooltip')
|
||||||
.first()
|
.first()
|
||||||
@@ -217,7 +232,7 @@ context(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2001-STKE-041
|
// 1002-STKE-041 1002-STKE-053
|
||||||
it(
|
it(
|
||||||
'Able to remove part of a stake against a validator',
|
'Able to remove part of a stake against a validator',
|
||||||
{ tags: '@smoke' },
|
{ tags: '@smoke' },
|
||||||
@@ -230,11 +245,11 @@ context(
|
|||||||
verifyUnstakedBalance(1.0);
|
verifyUnstakedBalance(1.0);
|
||||||
closeStakingDialog();
|
closeStakingDialog();
|
||||||
navigateTo(navigation.validators);
|
navigateTo(navigation.validators);
|
||||||
// 2001-STKE-040
|
// 1002-STKE-040
|
||||||
clickOnValidatorFromList(0);
|
clickOnValidatorFromList(0);
|
||||||
// 2001-STKE-044, 2001-STKE-048
|
// 1002-STKE-044, 1002-STKE-048
|
||||||
stakingValidatorPageRemoveStake('1');
|
stakingValidatorPageRemoveStake('1');
|
||||||
// 2001-STKE-049
|
// 1002-STKE-049
|
||||||
verifyNextEpochValue(2.0);
|
verifyNextEpochValue(2.0);
|
||||||
verifyUnstakedBalance(2.0);
|
verifyUnstakedBalance(2.0);
|
||||||
verifyStakedBalance(2.0);
|
verifyStakedBalance(2.0);
|
||||||
@@ -254,7 +269,7 @@ context(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 2001-STKE-045
|
// 1002-STKE-045
|
||||||
it('Able to remove a full stake against a validator', function () {
|
it('Able to remove a full stake against a validator', function () {
|
||||||
stakingPageAssociateTokens('3');
|
stakingPageAssociateTokens('3');
|
||||||
verifyUnstakedBalance(3.0);
|
verifyUnstakedBalance(3.0);
|
||||||
@@ -302,6 +317,7 @@ context(
|
|||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 1002-STKE-046 1002-STKE-047
|
||||||
it('Unable to remove a stake greater than staked amount next epoch for a validator', function () {
|
it('Unable to remove a stake greater than staked amount next epoch for a validator', function () {
|
||||||
stakingPageAssociateTokens('3');
|
stakingPageAssociateTokens('3');
|
||||||
verifyUnstakedBalance(3.0);
|
verifyUnstakedBalance(3.0);
|
||||||
@@ -379,6 +395,9 @@ context(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Disassociating some tokens - prioritizes unstaked tokens', function () {
|
it('Disassociating some tokens - prioritizes unstaked tokens', function () {
|
||||||
|
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||||
|
cy.reload();
|
||||||
|
ethereumWalletConnect();
|
||||||
stakingPageAssociateTokens('3');
|
stakingPageAssociateTokens('3');
|
||||||
verifyUnstakedBalance(3.0);
|
verifyUnstakedBalance(3.0);
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
@@ -401,7 +420,7 @@ context(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () {
|
it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () {
|
||||||
// 2001-STKE-004
|
// 1002-STKE-004
|
||||||
stakingPageAssociateTokens('3');
|
stakingPageAssociateTokens('3');
|
||||||
verifyUnstakedBalance(3.0);
|
verifyUnstakedBalance(3.0);
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
@@ -415,7 +434,7 @@ context(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () {
|
it('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () {
|
||||||
// 2001-STKE-004
|
// 1002-STKE-004
|
||||||
stakingPageAssociateTokens('3', { type: 'contract' });
|
stakingPageAssociateTokens('3', { type: 'contract' });
|
||||||
verifyUnstakedBalance(3.0);
|
verifyUnstakedBalance(3.0);
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
@@ -429,7 +448,7 @@ context(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () {
|
it('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () {
|
||||||
// 2001-STKE-004
|
// 1002-STKE-004
|
||||||
stakingPageAssociateTokens('3', { type: 'wallet' });
|
stakingPageAssociateTokens('3', { type: 'wallet' });
|
||||||
verifyUnstakedBalance(3.0);
|
verifyUnstakedBalance(3.0);
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
@@ -443,7 +462,7 @@ context(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () {
|
it('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () {
|
||||||
// 2001-STKE-004
|
// 1002-STKE-004
|
||||||
stakingPageAssociateTokens('6');
|
stakingPageAssociateTokens('6');
|
||||||
verifyUnstakedBalance(6.0);
|
verifyUnstakedBalance(6.0);
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
@@ -485,6 +504,7 @@ context(
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterEach('Teardown Wallet', function () {
|
afterEach('Teardown Wallet', function () {
|
||||||
|
navigateTo(navigation.home);
|
||||||
vegaWalletTeardown();
|
vegaWalletTeardown();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -495,7 +515,7 @@ context(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function verifyThisEpochValue(amount: number) {
|
function verifyThisEpochValue(amount: number) {
|
||||||
cy.getByTestId('stake-this-epoch', epochTimeout) // 2001-STKE-013
|
cy.getByTestId('stake-this-epoch', epochTimeout) // 1002-STKE-013
|
||||||
.contains(amount, epochTimeout)
|
.contains(amount, epochTimeout)
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ import {
|
|||||||
} from '../../support/staking.functions';
|
} from '../../support/staking.functions';
|
||||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
import {
|
import {
|
||||||
|
switchVegaWalletPubKey,
|
||||||
vegaWalletAssociate,
|
vegaWalletAssociate,
|
||||||
vegaWalletDisassociate,
|
vegaWalletDisassociate,
|
||||||
vegaWalletSetSpecifiedApprovalAmount,
|
vegaWalletSetSpecifiedApprovalAmount,
|
||||||
vegaWalletTeardown,
|
vegaWalletTeardown,
|
||||||
} from '../../support/wallet-teardown.functions';
|
} from '../../support/wallet-functions';
|
||||||
|
|
||||||
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
|
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
|
||||||
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
||||||
@@ -38,7 +39,7 @@ const associatedKey = '[data-testid="associated-key"]';
|
|||||||
const associatedAmount = '[data-testid="associated-amount"]';
|
const associatedAmount = '[data-testid="associated-amount"]';
|
||||||
const associateCompleteText = '[data-testid="transaction-complete-body"]';
|
const associateCompleteText = '[data-testid="transaction-complete-body"]';
|
||||||
const disassociationWarning = '[data-testid="disassociation-warning"]';
|
const disassociationWarning = '[data-testid="disassociation-warning"]';
|
||||||
const vegaWallet = '[data-testid="vega-wallet"]';
|
const vegaWallet = 'aside [data-testid="vega-wallet"]';
|
||||||
|
|
||||||
context(
|
context(
|
||||||
'Token association flow - with eth and vega wallets connected',
|
'Token association flow - with eth and vega wallets connected',
|
||||||
@@ -64,46 +65,38 @@ context(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
it('Able to associate tokens - from wallet', function () {
|
it(
|
||||||
//1004-ASSO-003
|
'Able to associate tokens - from wallet',
|
||||||
//1004-ASSO-005
|
{ tags: '@smoke' },
|
||||||
//1004-ASSO-009
|
function () {
|
||||||
//1004-ASSO-030
|
//1004-ASSO-003
|
||||||
//1004-ASSO-012
|
//1004-ASSO-005
|
||||||
//1004-ASSO-013
|
//1004-ASSO-009
|
||||||
//1004-ASSO-014
|
//1004-ASSO-030
|
||||||
//1004-ASSO-015
|
//1004-ASSO-012
|
||||||
//1004-ASSO-030
|
//1004-ASSO-013
|
||||||
//0005-ETXN-006
|
//1004-ASSO-014
|
||||||
//0005-ETXN-003
|
//1004-ASSO-015
|
||||||
//0005-ETXN-005
|
//1004-ASSO-030
|
||||||
stakingPageAssociateTokens('2', { skipConfirmation: true });
|
//0005-ETXN-006
|
||||||
|
//0005-ETXN-003
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
//0005-ETXN-005
|
||||||
'have.length.above',
|
stakingPageAssociateTokens('2', { skipConfirmation: true });
|
||||||
6
|
validateWalletCurrency('Associated', '0.00');
|
||||||
);
|
validateWalletCurrency('Pending association', '2.00');
|
||||||
validateWalletCurrency('Associated', '0.00');
|
validateWalletCurrency('Total associated after pending', '2.00');
|
||||||
validateWalletCurrency('Pending association', '2.00');
|
// 0005-ETXN-002
|
||||||
validateWalletCurrency('Total associated after pending', '2.00');
|
verifyEthWalletAssociatedBalance('2.0');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
|
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||||
|
cy.get(vegaWallet).within(() => {
|
||||||
// 0005-ETXN-002
|
|
||||||
verifyEthWalletAssociatedBalance('2.0');
|
|
||||||
|
|
||||||
verifyEthWalletTotalAssociatedBalance('2.0');
|
|
||||||
|
|
||||||
cy.get(vegaWallet)
|
|
||||||
.first()
|
|
||||||
.within(() => {
|
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||||
'contain',
|
'contain',
|
||||||
2.0
|
2.0
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
it('Able to disassociate all associated tokens - manually', function () {
|
it('Able to disassociate all associated tokens - manually', function () {
|
||||||
// 1004-ASSO-025
|
// 1004-ASSO-025
|
||||||
@@ -116,15 +109,11 @@ context(
|
|||||||
verifyEthWalletAssociatedBalance('2.0');
|
verifyEthWalletAssociatedBalance('2.0');
|
||||||
verifyEthWalletTotalAssociatedBalance('6,002.00');
|
verifyEthWalletTotalAssociatedBalance('6,002.00');
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
cy.getByTestId('epoch-countdown').should('be.visible');
|
||||||
stakingPageDisassociateTokens('2');
|
stakingPageDisassociateTokens('2');
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
|
||||||
'have.length.above',
|
|
||||||
6
|
|
||||||
);
|
|
||||||
validateWalletCurrency('Associated', '2.00');
|
validateWalletCurrency('Associated', '2.00');
|
||||||
validateWalletCurrency('Pending association', '2.00');
|
validateWalletCurrency('Pending association', '2.00');
|
||||||
validateWalletCurrency('Total associated after pending', '0.00');
|
validateWalletCurrency('Total associated after pending', '0.00');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
|
|
||||||
cy.get(
|
cy.get(
|
||||||
'[data-testid="eth-wallet-associated-balances"]:visible',
|
'[data-testid="eth-wallet-associated-balances"]:visible',
|
||||||
txTimeout
|
txTimeout
|
||||||
@@ -137,38 +126,26 @@ context(
|
|||||||
stakingPageAssociateTokens('1001', { approve: true });
|
stakingPageAssociateTokens('1001', { approve: true });
|
||||||
verifyEthWalletAssociatedBalance('1,001.00');
|
verifyEthWalletAssociatedBalance('1,001.00');
|
||||||
verifyEthWalletTotalAssociatedBalance('7,001.00');
|
verifyEthWalletTotalAssociatedBalance('7,001.00');
|
||||||
cy.get(vegaWallet)
|
cy.get(vegaWallet).within(() => {
|
||||||
.last()
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||||
.within(() => {
|
'contain',
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
'1,001.00'
|
||||||
'contain',
|
);
|
||||||
'1,001.00'
|
});
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to disassociate a partial amount of tokens currently associated', function () {
|
it('Able to disassociate a partial amount of tokens currently associated', function () {
|
||||||
stakingPageAssociateTokens('2');
|
stakingPageAssociateTokens('2');
|
||||||
cy.get(vegaWallet)
|
cy.get(vegaWallet).within(() => {
|
||||||
.first()
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||||
.within(() => {
|
});
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
2.0
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
cy.getByTestId('epoch-countdown').should('be.visible');
|
||||||
stakingPageDisassociateTokens('1');
|
stakingPageDisassociateTokens('1');
|
||||||
verifyEthWalletAssociatedBalance('1.0');
|
verifyEthWalletAssociatedBalance('1.0');
|
||||||
cy.get(vegaWallet)
|
cy.get(vegaWallet).within(() => {
|
||||||
.first()
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 1.0);
|
||||||
.within(() => {
|
});
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
1.0
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to disassociate all tokens - using max', function () {
|
it('Able to disassociate all tokens - using max', function () {
|
||||||
@@ -176,15 +153,11 @@ context(
|
|||||||
const warningText =
|
const warningText =
|
||||||
'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.';
|
'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.';
|
||||||
stakingPageAssociateTokens('2');
|
stakingPageAssociateTokens('2');
|
||||||
cy.get(vegaWallet)
|
cy.get(vegaWallet).within(() => {
|
||||||
.first()
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||||
.within(() => {
|
});
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
2.0
|
|
||||||
);
|
|
||||||
});
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
cy.getByTestId('epoch-countdown').should('be.visible');
|
||||||
cy.get(ethWalletDissociateButton).click();
|
cy.get(ethWalletDissociateButton).click();
|
||||||
cy.get(disassociationWarning).should('contain', warningText);
|
cy.get(disassociationWarning).should('contain', warningText);
|
||||||
stakingPageDisassociateAllTokens();
|
stakingPageDisassociateAllTokens();
|
||||||
@@ -202,14 +175,9 @@ context(
|
|||||||
'not.exist'
|
'not.exist'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
cy.get(vegaWallet)
|
cy.get(vegaWallet).within(() => {
|
||||||
.first()
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 0.0);
|
||||||
.within(() => {
|
});
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
0.0
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to associate and disassociate vesting contract tokens', function () {
|
it('Able to associate and disassociate vesting contract tokens', function () {
|
||||||
@@ -224,38 +192,22 @@ context(
|
|||||||
type: 'contract',
|
type: 'contract',
|
||||||
skipConfirmation: true,
|
skipConfirmation: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
|
||||||
'have.length.above',
|
|
||||||
6
|
|
||||||
);
|
|
||||||
validateWalletCurrency('Associated', '0.00');
|
validateWalletCurrency('Associated', '0.00');
|
||||||
validateWalletCurrency('Pending association', '2.00');
|
validateWalletCurrency('Pending association', '2.00');
|
||||||
validateWalletCurrency('Total associated after pending', '2.00');
|
validateWalletCurrency('Total associated after pending', '2.00');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
|
|
||||||
verifyEthWalletAssociatedBalance('2.0');
|
verifyEthWalletAssociatedBalance('2.0');
|
||||||
verifyEthWalletTotalAssociatedBalance('2.0');
|
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||||
cy.get(vegaWallet)
|
cy.get(vegaWallet).within(() => {
|
||||||
.first()
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||||
.within(() => {
|
});
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
2.0
|
|
||||||
);
|
|
||||||
});
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
||||||
stakingPageDisassociateTokens('1', {
|
stakingPageDisassociateTokens('1', {
|
||||||
type: 'contract',
|
type: 'contract',
|
||||||
skipConfirmation: true,
|
skipConfirmation: true,
|
||||||
});
|
});
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
|
||||||
'have.length.above',
|
|
||||||
6
|
|
||||||
);
|
|
||||||
validateWalletCurrency('Associated', '2.00');
|
validateWalletCurrency('Associated', '2.00');
|
||||||
validateWalletCurrency('Pending association', '1.00');
|
validateWalletCurrency('Pending association', '1.00');
|
||||||
validateWalletCurrency('Total associated after pending', '1.00');
|
validateWalletCurrency('Total associated after pending', '1.00');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
|
|
||||||
verifyEthWalletAssociatedBalance('1.0');
|
verifyEthWalletAssociatedBalance('1.0');
|
||||||
verifyEthWalletTotalAssociatedBalance('1.0');
|
verifyEthWalletTotalAssociatedBalance('1.0');
|
||||||
});
|
});
|
||||||
@@ -267,6 +219,7 @@ context(
|
|||||||
// 1004-ASSO-022
|
// 1004-ASSO-022
|
||||||
stakingPageAssociateTokens('21', { type: 'wallet' });
|
stakingPageAssociateTokens('21', { type: 'wallet' });
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
cy.getByTestId('epoch-countdown').should('be.visible');
|
||||||
stakingPageAssociateTokens('37', { type: 'contract' });
|
stakingPageAssociateTokens('37', { type: 'contract' });
|
||||||
cy.get(vestingContractSection)
|
cy.get(vestingContractSection)
|
||||||
.first()
|
.first()
|
||||||
@@ -286,28 +239,18 @@ context(
|
|||||||
);
|
);
|
||||||
cy.get(associatedAmount, txTimeout).should('contain', 21);
|
cy.get(associatedAmount, txTimeout).should('contain', 21);
|
||||||
});
|
});
|
||||||
cy.get(vegaWallet)
|
cy.get(vegaWallet).within(() => {
|
||||||
.first()
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 58);
|
||||||
.within(() => {
|
});
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
58
|
|
||||||
);
|
|
||||||
});
|
|
||||||
stakingPageDisassociateTokens('6', { type: 'contract' });
|
stakingPageDisassociateTokens('6', { type: 'contract' });
|
||||||
cy.get(vestingContractSection)
|
cy.get(vestingContractSection)
|
||||||
.first()
|
.first()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get(associatedAmount, txTimeout).should('contain', 31);
|
cy.get(associatedAmount, txTimeout).should('contain', 31);
|
||||||
});
|
});
|
||||||
cy.get(vegaWallet)
|
cy.get(vegaWallet).within(() => {
|
||||||
.first()
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 52);
|
||||||
.within(() => {
|
});
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
52
|
|
||||||
);
|
|
||||||
});
|
|
||||||
navigateTo(navigation.validators);
|
navigateTo(navigation.validators);
|
||||||
stakingPageDisassociateTokens('9', { type: 'wallet' });
|
stakingPageDisassociateTokens('9', { type: 'wallet' });
|
||||||
cy.get(vegaInWalletSection)
|
cy.get(vegaInWalletSection)
|
||||||
@@ -315,14 +258,9 @@ context(
|
|||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get(associatedAmount, txTimeout).should('contain', 12);
|
cy.get(associatedAmount, txTimeout).should('contain', 12);
|
||||||
});
|
});
|
||||||
cy.get(vegaWallet)
|
cy.get(vegaWallet).within(() => {
|
||||||
.first()
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 43);
|
||||||
.within(() => {
|
});
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
43
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Not able to associate more tokens than owned', function () {
|
it('Not able to associate more tokens than owned', function () {
|
||||||
@@ -339,14 +277,9 @@ context(
|
|||||||
// 1004-ASSO-004
|
// 1004-ASSO-004
|
||||||
it('Pending association outside of app is shown', function () {
|
it('Pending association outside of app is shown', function () {
|
||||||
vegaWalletAssociate('2');
|
vegaWalletAssociate('2');
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
|
||||||
'have.length.above',
|
|
||||||
6
|
|
||||||
);
|
|
||||||
validateWalletCurrency('Associated', '0.00');
|
validateWalletCurrency('Associated', '0.00');
|
||||||
validateWalletCurrency('Pending association', '2.00');
|
validateWalletCurrency('Pending association', '2.00');
|
||||||
validateWalletCurrency('Total associated after pending', '2.00');
|
validateWalletCurrency('Total associated after pending', '2.00');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
|
|
||||||
validateWalletCurrency('Associated', '2.00');
|
validateWalletCurrency('Associated', '2.00');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -355,14 +288,9 @@ context(
|
|||||||
cy.wrap(validateWalletCurrency('Associated', '2.00')).then(() => {
|
cy.wrap(validateWalletCurrency('Associated', '2.00')).then(() => {
|
||||||
vegaWalletDisassociate('2');
|
vegaWalletDisassociate('2');
|
||||||
});
|
});
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
|
||||||
'have.length.above',
|
|
||||||
6
|
|
||||||
);
|
|
||||||
validateWalletCurrency('Associated', '2.00');
|
validateWalletCurrency('Associated', '2.00');
|
||||||
validateWalletCurrency('Pending association', '2.00');
|
validateWalletCurrency('Pending association', '2.00');
|
||||||
validateWalletCurrency('Total associated after pending', '0.00');
|
validateWalletCurrency('Total associated after pending', '0.00');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
|
|
||||||
validateWalletCurrency('Associated', '0.00');
|
validateWalletCurrency('Associated', '0.00');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -374,21 +302,15 @@ context(
|
|||||||
Cypress.env('vegaWalletPublicKey')
|
Cypress.env('vegaWalletPublicKey')
|
||||||
);
|
);
|
||||||
|
|
||||||
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
|
switchVegaWalletPubKey();
|
||||||
cy.get('[data-testid="select-keypair-button"]').eq(0).click();
|
|
||||||
cy.get(connectedVegaKey).should(
|
cy.get(connectedVegaKey).should(
|
||||||
'have.text',
|
'have.text',
|
||||||
Cypress.env('vegaWalletPublicKey2')
|
Cypress.env('vegaWalletPublicKey2')
|
||||||
);
|
);
|
||||||
stakingPageAssociateTokens('2');
|
stakingPageAssociateTokens('2');
|
||||||
cy.get(vegaWallet)
|
cy.get(vegaWallet).within(() => {
|
||||||
.first()
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||||
.within(() => {
|
});
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
2.0
|
|
||||||
);
|
|
||||||
});
|
|
||||||
cy.get(associateCompleteText).should(
|
cy.get(associateCompleteText).should(
|
||||||
'have.text',
|
'have.text',
|
||||||
`Vega key ${Cypress.env(
|
`Vega key ${Cypress.env(
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
waitForSpinner,
|
waitForSpinner,
|
||||||
} from '../../support/common.functions';
|
} from '../../support/common.functions';
|
||||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
import { depositAsset } from '../../support/wallet-teardown.functions';
|
import { depositAsset } from '../../support/wallet-functions';
|
||||||
|
|
||||||
const withdraw = 'withdraw';
|
const withdraw = 'withdraw';
|
||||||
const withdrawalForm = 'withdraw-form';
|
const withdrawalForm = 'withdraw-form';
|
||||||
@@ -15,13 +15,7 @@ const balanceAvailable = 'BALANCE_AVAILABLE_value';
|
|||||||
const withdrawalThreshold = 'WITHDRAWAL_THRESHOLD_value';
|
const withdrawalThreshold = 'WITHDRAWAL_THRESHOLD_value';
|
||||||
const delayTime = 'DELAY_TIME_value';
|
const delayTime = 'DELAY_TIME_value';
|
||||||
const submitWithdrawalButton = 'submit-withdrawal';
|
const submitWithdrawalButton = 'submit-withdrawal';
|
||||||
const dialogTitle = 'dialog-title';
|
|
||||||
const dialogClose = 'dialog-close';
|
const dialogClose = 'dialog-close';
|
||||||
const txExplorerLink = 'tx-block-explorer';
|
|
||||||
const withdrawalAssetSymbol = 'withdrawal-asset-symbol';
|
|
||||||
const withdrawalAmount = 'withdrawal-amount';
|
|
||||||
const withdrawalRecipient = 'withdrawal-recipient';
|
|
||||||
const withdrawFundsButton = 'withdraw-funds';
|
|
||||||
const completeWithdrawalButton = 'complete-withdrawal';
|
const completeWithdrawalButton = 'complete-withdrawal';
|
||||||
const tableTxHash = '[col-id="txHash"]';
|
const tableTxHash = '[col-id="txHash"]';
|
||||||
const tableAssetSymbol = '[col-id="asset.symbol"]';
|
const tableAssetSymbol = '[col-id="asset.symbol"]';
|
||||||
@@ -30,14 +24,16 @@ const tableReceiverAddress = '[col-id="details.receiverAddress"]';
|
|||||||
const tableWithdrawnTimeStamp = '[col-id="withdrawnTimestamp"]';
|
const tableWithdrawnTimeStamp = '[col-id="withdrawnTimestamp"]';
|
||||||
const tableWithdrawnStatus = '[col-id="status"]';
|
const tableWithdrawnStatus = '[col-id="status"]';
|
||||||
const tableCreatedTimeStamp = '[col-id="createdTimestamp"]';
|
const tableCreatedTimeStamp = '[col-id="createdTimestamp"]';
|
||||||
const toastContent = 'toast-content';
|
const toast = 'toast';
|
||||||
const toastPanel = 'toast-panel';
|
const toastPanel = 'toast-panel';
|
||||||
|
const toastClose = 'toast-close';
|
||||||
|
const withdrawalDialogContent = 'dialog-content';
|
||||||
|
const toastCompleteWithdrawal = 'toast-complete-withdrawal';
|
||||||
const usdtName = 'USDC (local)';
|
const usdtName = 'USDC (local)';
|
||||||
const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0';
|
const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0';
|
||||||
const usdcSymbol = 'tUSDC';
|
const usdcSymbol = 'tUSDC';
|
||||||
const usdtSelectValue =
|
const usdtSelectValue =
|
||||||
'993ed98f4f770d91a796faab1738551193ba45c62341d20597df70fea6704ede';
|
'993ed98f4f770d91a796faab1738551193ba45c62341d20597df70fea6704ede';
|
||||||
const truncatedWithdrawalEthAddress = '0xEe7D…22d94F';
|
|
||||||
const formValidationError = 'input-error-text';
|
const formValidationError = 'input-error-text';
|
||||||
const txTimeout = Cypress.env('txTimeout');
|
const txTimeout = Cypress.env('txTimeout');
|
||||||
|
|
||||||
@@ -59,6 +55,10 @@ context(
|
|||||||
navigateTo(navigation.withdraw);
|
navigateTo(navigation.withdraw);
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
ethereumWalletConnect();
|
ethereumWalletConnect();
|
||||||
|
cy.getByTestId('currency-title', txTimeout).should(
|
||||||
|
'contain.text',
|
||||||
|
usdtName
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to open withdrawal form with vega wallet connected', function () {
|
it('Able to open withdrawal form with vega wallet connected', function () {
|
||||||
@@ -73,7 +73,10 @@ context(
|
|||||||
it('Unable to submit withdrawal with invalid fields', function () {
|
it('Unable to submit withdrawal with invalid fields', function () {
|
||||||
cy.getByTestId(withdraw).should('be.visible').click();
|
cy.getByTestId(withdraw).should('be.visible').click();
|
||||||
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
||||||
cy.get('select').select(usdtSelectValue, { force: true });
|
cy.getByTestId('select-asset').click();
|
||||||
|
cy.get('select')
|
||||||
|
.select(usdtSelectValue, { force: true })
|
||||||
|
.should('have.value', usdtSelectValue);
|
||||||
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
cy.getByTestId(formValidationError).should('have.length', 1);
|
cy.getByTestId(formValidationError).should('have.length', 1);
|
||||||
@@ -93,62 +96,75 @@ context(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to withdraw asset: -eth wallet connected -withdraw funds button', function () {
|
it(
|
||||||
// fill in withdrawal form
|
'Able to withdraw asset: -eth wallet connected -withdraw funds button',
|
||||||
cy.getByTestId(withdraw).should('be.visible').click();
|
{ tags: '@smoke' },
|
||||||
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
function () {
|
||||||
cy.get('select').select(usdtSelectValue, { force: true });
|
// fill in withdrawal form
|
||||||
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
cy.getByTestId(withdraw).should('be.visible').click();
|
||||||
cy.getByTestId(withdrawalThreshold).should(
|
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
||||||
'have.text',
|
cy.getByTestId('select-asset').click();
|
||||||
'100,000.00000T'
|
cy.get('select')
|
||||||
);
|
.select(usdtSelectValue, { force: true })
|
||||||
cy.getByTestId(delayTime).should('have.text', 'None');
|
.should('have.value', usdtSelectValue);
|
||||||
cy.getByTestId(amountInput).click().type('120');
|
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(withdrawalThreshold).should(
|
||||||
});
|
'have.text',
|
||||||
|
'100,000.00000T'
|
||||||
cy.contains('Awaiting network confirmation').should('be.visible');
|
);
|
||||||
// assert withdrawal request
|
cy.getByTestId(delayTime).should('have.text', 'None');
|
||||||
cy.getByTestId(dialogTitle, txTimeout).should(
|
cy.getByTestId(amountInput).click().type('120');
|
||||||
'have.text',
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
'Transaction complete'
|
|
||||||
);
|
|
||||||
cy.getByTestId(txExplorerLink)
|
|
||||||
.should('have.attr', 'href')
|
|
||||||
.and('contain', '/txs/');
|
|
||||||
cy.getByTestId(withdrawalAssetSymbol).should('have.text', usdcSymbol);
|
|
||||||
cy.getByTestId(withdrawalAmount).should('have.text', '120.00');
|
|
||||||
cy.getByTestId(withdrawalRecipient)
|
|
||||||
.should('have.text', truncatedWithdrawalEthAddress)
|
|
||||||
.and('have.attr', 'href')
|
|
||||||
.and('contain', `/address/${Cypress.env('ethWalletPublicKey')}`);
|
|
||||||
cy.getByTestId(withdrawFundsButton).click();
|
|
||||||
// withdrawal complete
|
|
||||||
cy.getByTestId(dialogTitle, txTimeout).should(
|
|
||||||
'have.text',
|
|
||||||
'Withdraw asset complete'
|
|
||||||
);
|
|
||||||
cy.getByTestId(dialogClose).click();
|
|
||||||
// withdrawal history for complete withdrawal displayed
|
|
||||||
cy.get(tableWithdrawnStatus)
|
|
||||||
.eq(1, txTimeout)
|
|
||||||
.should('have.text', 'Completed')
|
|
||||||
.parent()
|
|
||||||
.within(() => {
|
|
||||||
cy.get(tableAssetSymbol).should('have.text', usdcSymbol);
|
|
||||||
cy.get(tableAmount).should('have.text', '120.00');
|
|
||||||
cy.get(tableReceiverAddress)
|
|
||||||
.find('a')
|
|
||||||
.should('have.attr', 'href')
|
|
||||||
.and('contain', 'https://sepolia.etherscan.io/address/');
|
|
||||||
cy.get(tableWithdrawnTimeStamp).should('not.be.empty');
|
|
||||||
cy.get(tableTxHash)
|
|
||||||
.find('a')
|
|
||||||
.should('have.attr', 'href')
|
|
||||||
.and('contain', 'https://sepolia.etherscan.io/tx/');
|
|
||||||
});
|
});
|
||||||
});
|
// assert withdrawal request
|
||||||
|
cy.getByTestId(toast)
|
||||||
|
.first(txTimeout)
|
||||||
|
.should('contain.text', 'Funds unlocked')
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId('external-link').should('exist');
|
||||||
|
cy.getByTestId(toastPanel).should(
|
||||||
|
'contain.text',
|
||||||
|
'Withdraw 120.00 tUSDC'
|
||||||
|
);
|
||||||
|
cy.getByTestId(toastCompleteWithdrawal).click();
|
||||||
|
cy.getByTestId(toastClose).click();
|
||||||
|
});
|
||||||
|
// withdrawal complete
|
||||||
|
cy.getByTestId(toast)
|
||||||
|
.first(txTimeout)
|
||||||
|
.should('contain.text', 'The withdrawal has been approved.')
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId(toastPanel).should(
|
||||||
|
'contain.text',
|
||||||
|
'Withdraw 120.00 tUSDC'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
cy.getByTestId(toast)
|
||||||
|
.last(txTimeout)
|
||||||
|
.should('contain.text', 'Transaction confirmed')
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId('external-link').should('exist');
|
||||||
|
});
|
||||||
|
// withdrawal history for complete withdrawal displayed
|
||||||
|
cy.get(tableWithdrawnStatus)
|
||||||
|
.eq(1, txTimeout)
|
||||||
|
.should('have.text', 'Completed')
|
||||||
|
.parent()
|
||||||
|
.within(() => {
|
||||||
|
cy.get(tableAssetSymbol).should('have.text', usdcSymbol);
|
||||||
|
cy.get(tableAmount).should('have.text', '120.00');
|
||||||
|
cy.get(tableReceiverAddress)
|
||||||
|
.find('a')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', 'https://sepolia.etherscan.io/address/');
|
||||||
|
cy.get(tableWithdrawnTimeStamp).should('not.be.empty');
|
||||||
|
cy.get(tableTxHash)
|
||||||
|
.find('a')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', 'https://sepolia.etherscan.io/tx/');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
it('Able to withdraw asset: -eth wallet not connected', function () {
|
it('Able to withdraw asset: -eth wallet not connected', function () {
|
||||||
const ethWalletAddress = Cypress.env('ethWalletPublicKey');
|
const ethWalletAddress = Cypress.env('ethWalletPublicKey');
|
||||||
@@ -157,7 +173,10 @@ context(
|
|||||||
// fill in withdrawal form
|
// fill in withdrawal form
|
||||||
cy.getByTestId(withdraw).should('be.visible').click();
|
cy.getByTestId(withdraw).should('be.visible').click();
|
||||||
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
||||||
cy.get('select').select(usdtSelectValue, { force: true });
|
cy.getByTestId('select-asset').click();
|
||||||
|
cy.get('select')
|
||||||
|
.select(usdtSelectValue, { force: true })
|
||||||
|
.should('have.value', usdtSelectValue);
|
||||||
cy.getByTestId(ethAddressInput).should('be.empty');
|
cy.getByTestId(ethAddressInput).should('be.empty');
|
||||||
cy.getByTestId(amountInput).click().type('110');
|
cy.getByTestId(amountInput).click().type('110');
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
@@ -168,13 +187,17 @@ context(
|
|||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.contains('Awaiting network confirmation').should('be.visible');
|
cy.getByTestId(toast)
|
||||||
// assert withdrawal request
|
.first(txTimeout)
|
||||||
cy.getByTestId(dialogTitle, txTimeout).should(
|
.should('contain.text', 'Funds unlocked')
|
||||||
'have.text',
|
.within(() => {
|
||||||
'Transaction complete'
|
cy.getByTestId('external-link').should('exist');
|
||||||
);
|
cy.getByTestId(toastPanel).should(
|
||||||
cy.getByTestId(dialogClose).click();
|
'contain.text',
|
||||||
|
'Withdraw 110.00 tUSDC'
|
||||||
|
);
|
||||||
|
cy.getByTestId(toastClose).click();
|
||||||
|
});
|
||||||
cy.get(tableTxHash)
|
cy.get(tableTxHash)
|
||||||
.eq(1)
|
.eq(1)
|
||||||
.should('have.text', 'Complete withdrawal')
|
.should('have.text', 'Complete withdrawal')
|
||||||
@@ -189,28 +212,78 @@ context(
|
|||||||
cy.get(tableCreatedTimeStamp).should('not.be.empty');
|
cy.get(tableCreatedTimeStamp).should('not.be.empty');
|
||||||
});
|
});
|
||||||
ethereumWalletConnect();
|
ethereumWalletConnect();
|
||||||
cy.getByTestId(completeWithdrawalButton).click();
|
cy.getByTestId(completeWithdrawalButton).first().click();
|
||||||
cy.getByTestId(toastContent)
|
cy.getByTestId(toast)
|
||||||
.last()
|
.last(txTimeout)
|
||||||
.should('contain.text', 'Awaiting confirmation')
|
.should('contain.text', 'Awaiting confirmation')
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId('external-link').should('exist');
|
cy.getByTestId('external-link').should('exist');
|
||||||
});
|
});
|
||||||
cy.getByTestId(toastContent)
|
cy.getByTestId(toast)
|
||||||
.first()
|
.first(txTimeout)
|
||||||
.should('contain.text', 'The withdrawal has been approved.')
|
.should('contain.text', 'The withdrawal has been approved.')
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId(toastPanel).should('contain.text', '110.00', 'tUSDC');
|
cy.getByTestId(toastPanel).should('contain.text', '110.00', 'tUSDC');
|
||||||
});
|
});
|
||||||
cy.getByTestId(toastContent)
|
cy.getByTestId(toast)
|
||||||
.last()
|
.last(txTimeout)
|
||||||
.should('contain.text', 'Transaction confirmed')
|
.should('contain.text', 'Transaction confirmed')
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId('external-link').should('exist');
|
cy.getByTestId('external-link').should('exist');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Unable to withdraw asset on pub key view', function () {
|
it('Should be able to see withdrawal details from toast', function () {
|
||||||
|
cy.getByTestId(withdraw).click();
|
||||||
|
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
||||||
|
cy.getByTestId('select-asset').click();
|
||||||
|
cy.get('select')
|
||||||
|
.select(usdtSelectValue, { force: true })
|
||||||
|
.should('have.value', usdtSelectValue);
|
||||||
|
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||||
|
cy.getByTestId(withdrawalThreshold).should(
|
||||||
|
'have.text',
|
||||||
|
'100,000.00000T'
|
||||||
|
);
|
||||||
|
cy.getByTestId(amountInput).click().type('50');
|
||||||
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
|
});
|
||||||
|
cy.getByTestId(toast)
|
||||||
|
.first(txTimeout)
|
||||||
|
.should('contain.text', 'Funds unlocked')
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId('external-link').should('exist');
|
||||||
|
cy.getByTestId(toastPanel).should(
|
||||||
|
'contain.text',
|
||||||
|
'Withdraw 50.00 tUSDC'
|
||||||
|
);
|
||||||
|
cy.contains('save your withdrawal details').click();
|
||||||
|
});
|
||||||
|
cy.getByTestId(withdrawalDialogContent)
|
||||||
|
.last()
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId('assetSource_value').should(
|
||||||
|
'have.text',
|
||||||
|
'0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0'
|
||||||
|
);
|
||||||
|
cy.getByTestId('amount_value').should('have.text', '5000000');
|
||||||
|
cy.getByTestId('nonce_value').invoke('text').should('not.be.empty');
|
||||||
|
cy.getByTestId('signatures_value')
|
||||||
|
.invoke('text')
|
||||||
|
.should('not.be.empty');
|
||||||
|
cy.getByTestId('targetAddress_value').should(
|
||||||
|
'have.text',
|
||||||
|
Cypress.env('ethWalletPublicKey')
|
||||||
|
);
|
||||||
|
cy.getByTestId('creation_value')
|
||||||
|
.invoke('text')
|
||||||
|
.should('not.be.empty');
|
||||||
|
});
|
||||||
|
cy.getByTestId(dialogClose).click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Skipping test due to bug #3882
|
||||||
|
it.skip('Unable to withdraw asset on pub key view', function () {
|
||||||
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey');
|
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey');
|
||||||
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
|
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
|
||||||
|
|
||||||
@@ -221,13 +294,17 @@ context(
|
|||||||
cy.connectPublicKey(vegaWalletPubKey);
|
cy.connectPublicKey(vegaWalletPubKey);
|
||||||
cy.getByTestId(withdraw).should('be.visible').click();
|
cy.getByTestId(withdraw).should('be.visible').click();
|
||||||
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
||||||
cy.get('select').select(usdtSelectValue, { force: true });
|
cy.getByTestId('select-asset').click();
|
||||||
|
cy.get('select')
|
||||||
|
.select(usdtSelectValue, { force: true })
|
||||||
|
.should('have.value', usdtSelectValue);
|
||||||
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||||
cy.getByTestId(amountInput).click().type('100');
|
cy.getByTestId(amountInput).click().type('100');
|
||||||
|
cy.pause();
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.getByTestId('dialog-content')
|
cy.getByTestId(withdrawalDialogContent)
|
||||||
.last()
|
.last()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get('h1').should('have.text', 'Transaction failed');
|
cy.get('h1').should('have.text', 'Transaction failed');
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
import { mockNetworkUpgradeProposal } from '../../support/proposal.functions';
|
import { mockNetworkUpgradeProposal } from '../../support/proposal.functions';
|
||||||
|
|
||||||
const proposalDocumentationLink = '[data-testid="proposal-documentation-link"]';
|
const proposalDocumentationLink = '[data-testid="proposal-documentation-link"]';
|
||||||
const newProposalLink = '[data-testid="new-proposal-link"]';
|
|
||||||
const governanceDocsUrl = 'https://vega.xyz/governance';
|
const governanceDocsUrl = 'https://vega.xyz/governance';
|
||||||
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
|
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
|
||||||
|
|
||||||
@@ -32,6 +31,14 @@ context(
|
|||||||
verifyPageHeader('Proposals');
|
verifyPageHeader('Proposals');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 3002-PROP-023 3004-PMAC-002 3005-PASN-002 3006-PASC-002 3007-PNEC-002 3008-PFRO-003
|
||||||
|
it('should have button for link to more information on proposals', function () {
|
||||||
|
const proposalsUrl = 'https://docs.vega.xyz/mainnet/tutorials/proposals';
|
||||||
|
cy.getByTestId('new-proposal-link')
|
||||||
|
.find('a')
|
||||||
|
.should('have.attr', 'href', proposalsUrl);
|
||||||
|
});
|
||||||
|
|
||||||
it('should be able to see a working link for - find out more about Vega governance', function () {
|
it('should be able to see a working link for - find out more about Vega governance', function () {
|
||||||
// 3001-VOTE-001
|
// 3001-VOTE-001
|
||||||
cy.get(proposalDocumentationLink)
|
cy.get(proposalDocumentationLink)
|
||||||
@@ -54,17 +61,62 @@ context(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should be able to see button for - new proposal', function () {
|
// 3007-PNE-021
|
||||||
// 3001-VOTE-002
|
it('should have documentation links for network parameter proposal', function () {
|
||||||
cy.get(newProposalLink)
|
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||||
.should('be.visible')
|
cy.getByTestId('proposal-docs-link')
|
||||||
.and('have.text', 'New proposal')
|
.find('a')
|
||||||
.and('have.attr', 'href')
|
.should('have.attr', 'href')
|
||||||
.and('equal', '/proposals/propose');
|
.and('contain', '/tutorials/proposals/network-parameter-proposal');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () {
|
// 3003-PMAN-002 3003-PMAN-005
|
||||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
it('should have documentation links for new market proposal', function () {
|
||||||
|
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||||
|
cy.getByTestId('proposal-docs-link')
|
||||||
|
.find('a')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', '/tutorials/proposals/new-market-proposal');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3004-PMAC-005
|
||||||
|
it('should have documentation links for update market proposal', function () {
|
||||||
|
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||||
|
cy.getByTestId('proposal-docs-link')
|
||||||
|
.find('a')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', '/tutorials/proposals/update-market-proposal');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3005-PASN-002 005-PASN-005
|
||||||
|
it('should have documentation links for new asset proposal', function () {
|
||||||
|
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||||
|
cy.getByTestId('proposal-docs-link')
|
||||||
|
.find('a')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', '/tutorials/proposals/new-asset-proposal');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3006-PASC-002 3006-PASC-005
|
||||||
|
it('should have documentation links for update asset proposal', function () {
|
||||||
|
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||||
|
cy.getByTestId('proposal-docs-link')
|
||||||
|
.find('a')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', '/tutorials/proposals/update-asset-proposal');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3008-PFRO-003 3008-PFRO-017
|
||||||
|
it('should have documentation links for freeform proposal', function () {
|
||||||
|
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||||
|
cy.getByTestId('proposal-docs-link')
|
||||||
|
.find('a')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', '/tutorials/proposals/freeform-proposal');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
cy.get(connectToVegaWalletButton)
|
cy.get(connectToVegaWalletButton)
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.and('have.text', 'Connect Vega wallet');
|
.and('have.text', 'Connect Vega wallet');
|
||||||
@@ -128,6 +180,7 @@ context(
|
|||||||
.first()
|
.first()
|
||||||
.find('[data-testid="view-proposal-btn"]')
|
.find('[data-testid="view-proposal-btn"]')
|
||||||
.click();
|
.click();
|
||||||
|
cy.url().should('contain', '/protocol-upgrades/v1');
|
||||||
cy.getByTestId('protocol-upgrade-proposal').within(() => {
|
cy.getByTestId('protocol-upgrade-proposal').within(() => {
|
||||||
cy.get('h1').should('have.text', 'Vega Release v1');
|
cy.get('h1').should('have.text', 'Vega Release v1');
|
||||||
cy.getByTestId('protocol-upgrade-block-height').should(
|
cy.getByTestId('protocol-upgrade-block-height').should(
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
goToMakeNewProposal,
|
goToMakeNewProposal,
|
||||||
governanceProposalType,
|
governanceProposalType,
|
||||||
} from '../../support/governance.functions';
|
} from '../../support/governance.functions';
|
||||||
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions';
|
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-functions';
|
||||||
|
|
||||||
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey2');
|
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey2');
|
||||||
const vegaPubkeyTruncated = Cypress.env('vegaWalletPublicKey2Short');
|
const vegaPubkeyTruncated = Cypress.env('vegaWalletPublicKey2Short');
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||||
import {
|
import {
|
||||||
navigation,
|
navigation,
|
||||||
verifyPageHeader,
|
verifyPageHeader,
|
||||||
verifyTabHighlighted,
|
verifyTabHighlighted,
|
||||||
} from '../../support/common.functions';
|
} from '../../support/common.functions';
|
||||||
import { clickOnValidatorFromList } from '../../support/staking.functions';
|
import {
|
||||||
|
clickOnValidatorFromList,
|
||||||
|
waitForBeginningOfEpoch,
|
||||||
|
} from '../../support/staking.functions';
|
||||||
|
import { previousEpochData } from '../../fixtures/mocks/previous-epoch';
|
||||||
|
|
||||||
const guideLink = '[data-testid="staking-guide-link"]';
|
const guideLink = '[data-testid="staking-guide-link"]';
|
||||||
const validatorTitle = '[data-testid="validator-node-title"]';
|
const validatorTitle = '[data-testid="validator-node-title"]';
|
||||||
@@ -27,7 +32,7 @@ const normalisedVotingPowerToolTip =
|
|||||||
'[data-testid="normalised-voting-power-tooltip"]';
|
'[data-testid="normalised-voting-power-tooltip"]';
|
||||||
const performancePenaltyToolTip = '[data-testid="performance-penalty-tooltip"]';
|
const performancePenaltyToolTip = '[data-testid="performance-penalty-tooltip"]';
|
||||||
const overstakedPenaltyToolTip = '[data-testid="overstaked-penalty-tooltip"]';
|
const overstakedPenaltyToolTip = '[data-testid="overstaked-penalty-tooltip"]';
|
||||||
const totalPenaltyToolTip = '[data-testid="total-penalty-tooltip"]';
|
const multisigPenaltyToolTip = '[data-testid="multisig-error-tooltip"]';
|
||||||
const epochCountDown = '[data-testid="epoch-countdown"]';
|
const epochCountDown = '[data-testid="epoch-countdown"]';
|
||||||
const stakeNumberRegex = /^\d{1,3}(,\d{3})*(\.\d+)?$/;
|
const stakeNumberRegex = /^\d{1,3}(,\d{3})*(\.\d+)?$/;
|
||||||
|
|
||||||
@@ -37,206 +42,226 @@ context('Validators Page - verify elements on page', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('with wallets disconnected', { tags: '@smoke' }, function () {
|
describe('with wallets disconnected', { tags: '@smoke' }, function () {
|
||||||
describe('description section', function () {
|
it('Should have validators tab highlighted', function () {
|
||||||
it('Should have validators tab highlighted', function () {
|
verifyTabHighlighted(navigation.validators);
|
||||||
verifyTabHighlighted(navigation.validators);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should have validators ON VEGA header visible', function () {
|
|
||||||
verifyPageHeader('Validators');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should have Staking Guide link visible', function () {
|
|
||||||
// 2001-STKE-003
|
|
||||||
cy.get(guideLink)
|
|
||||||
.should('be.visible')
|
|
||||||
.and('have.text', 'Read more about staking on Vega')
|
|
||||||
.and(
|
|
||||||
'have.attr',
|
|
||||||
'href',
|
|
||||||
'https://docs.vega.xyz/mainnet/concepts/vega-chain/#staking-on-vega'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
describe(
|
|
||||||
'Should be able to see validator list from the staking page',
|
|
||||||
{ tags: '@regression' },
|
|
||||||
function () {
|
|
||||||
// 2001-STKE-050
|
|
||||||
it('Should be able to see validator names', function () {
|
|
||||||
cy.get('[col-id="validator"] > div > span')
|
|
||||||
.should('have.length.at.least', 1)
|
|
||||||
.each(($name) => {
|
|
||||||
cy.wrap($name).should('not.be.empty');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see validator stake', function () {
|
it('Should have validators ON VEGA header visible', function () {
|
||||||
cy.getByTestId('total-stake')
|
verifyPageHeader('Validators');
|
||||||
.should('have.length.at.least', 1)
|
});
|
||||||
.each(($stake) => {
|
|
||||||
cy.wrap($stake).should('not.be.empty');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see validator stake tooltip', function () {
|
it('Should have Staking Guide link visible', function () {
|
||||||
cy.getByTestId('total-stake').first().realHover();
|
// 1002-STKE-003
|
||||||
|
cy.get(guideLink)
|
||||||
|
.should('be.visible')
|
||||||
|
.and('have.text', 'Read more about staking on Vega')
|
||||||
|
.and(
|
||||||
|
'have.attr',
|
||||||
|
'href',
|
||||||
|
'https://docs.vega.xyz/mainnet/concepts/vega-chain/#staking-on-vega'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
cy.get(stakedByOperatorToolTip)
|
// 1002-STKE-032
|
||||||
.invoke('text')
|
it('Should have button to connect vega wallet in validator page', function () {
|
||||||
.should('contain', 'Staked by operator: 3,000.00');
|
clickOnValidatorFromList(0);
|
||||||
cy.get(stakedByDelegatesToolTip)
|
cy.getByTestId('connect-to-vega-wallet-btn').should('be.visible');
|
||||||
.invoke('text')
|
cy.visit('/validators');
|
||||||
.should('contain', 'Staked by delegates: 0.00');
|
});
|
||||||
cy.get(totalStakedToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Total stake: 3,000.00');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see validator normalised voting power', function () {
|
|
||||||
cy.getByTestId('normalised-voting-power')
|
|
||||||
.should('have.length.at.least', 1)
|
|
||||||
.each(($vPower) => {
|
|
||||||
cy.wrap($vPower).should('not.be.empty');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see validator normalised voting power tooltip', function () {
|
|
||||||
cy.getByTestId('normalised-voting-power').first().realHover();
|
|
||||||
|
|
||||||
cy.get(unnormalisedVotingPowerToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Unnormalised voting power: 20.00%');
|
|
||||||
cy.get(normalisedVotingPowerToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Normalised voting power: 50.00%');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2002-SINC-018
|
|
||||||
it('Should be able to see validator total penalties', function () {
|
|
||||||
cy.getByTestId('total-penalty')
|
|
||||||
.should('have.length.at.least', 1)
|
|
||||||
.each(($penalties) => {
|
|
||||||
cy.wrap($penalties).should('contain.text', '0%');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see validator penalties tooltip', function () {
|
|
||||||
cy.getByTestId('total-penalty').realHover();
|
|
||||||
|
|
||||||
cy.get(performancePenaltyToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Performance penalty: 0.00%');
|
|
||||||
cy.get(overstakedPenaltyToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Overstaked penalty: 60.00%'); // value not asserted due to #2886
|
|
||||||
cy.get(totalPenaltyToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Total penalties: 60.00%');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see validator pending stake', function () {
|
|
||||||
cy.getByTestId('total-pending-stake')
|
|
||||||
.should('have.length.at.least', 1)
|
|
||||||
.each(($pendingStake) => {
|
|
||||||
cy.wrap($pendingStake).should('contain.text', '0.00');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2001-STKE-050
|
|
||||||
describe(
|
|
||||||
'Should be able to see static information about a validator',
|
|
||||||
{ tags: '@smoke' },
|
|
||||||
function () {
|
|
||||||
before('connect wallets and click on validator', function () {
|
|
||||||
cy.connectVegaWallet();
|
|
||||||
clickOnValidatorFromList(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2001-STKE-006
|
|
||||||
it('Should be able to see validator name', function () {
|
|
||||||
cy.get(validatorTitle).should('not.be.empty');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2001-STKE-007
|
|
||||||
it('Should be able to see validator id', function () {
|
|
||||||
cy.get(validatorId).should('not.be.empty');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2001-STKE-008
|
|
||||||
it('Should be able to see validator public key', function () {
|
|
||||||
cy.get(validatorPubKey).should('not.be.empty');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2001-STKE-010
|
|
||||||
it('Should be able to see Ethereum address', function () {
|
|
||||||
cy.get(ethAddressLink)
|
|
||||||
.should('not.be.empty')
|
|
||||||
.and('have.attr', 'href');
|
|
||||||
});
|
|
||||||
// TODO validators missing url for more information about them 2001-STKE-09
|
|
||||||
|
|
||||||
it('Should be able to see validator status', function () {
|
|
||||||
cy.get(validatorStatus).should('have.text', 'Consensus');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2001-STKE-012
|
|
||||||
it('Should be able to see total stake', function () {
|
|
||||||
cy.get(totalStake).invoke('text').should('match', stakeNumberRegex);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see pending stake', function () {
|
|
||||||
cy.get(pendingStake).invoke('text').should('match', stakeNumberRegex);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see staked by operator', function () {
|
|
||||||
cy.get(stakedByOperator)
|
|
||||||
.invoke('text')
|
|
||||||
.should('match', stakeNumberRegex);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see staked by delegates', function () {
|
|
||||||
cy.get(stakedByDelegates)
|
|
||||||
.invoke('text')
|
|
||||||
.should('match', stakeNumberRegex);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2001-STKE-051
|
|
||||||
it('Should be able to see stake share in percentage', function () {
|
|
||||||
cy.get(stakeShare)
|
|
||||||
.invoke('text')
|
|
||||||
.then(($stakePercentage) => {
|
|
||||||
// The pattern must start at a word boundary (\b).
|
|
||||||
// The pattern cannot be immediately preceded by a dot ((?<!\.)).
|
|
||||||
// The pattern can be one of the following:
|
|
||||||
// A percentage value of zero (0%), or
|
|
||||||
// A non-zero percentage value that can be:
|
|
||||||
// A single digit (\d) between 0 and 9, or
|
|
||||||
// A two-digit number between 0 and 99 (\d{1,2}), or
|
|
||||||
// The number 100.
|
|
||||||
// The pattern can optionally include a decimal point and one or more digits after the decimal point ((?:(?<!100)\.\d+)?). However, if the number is 100, it cannot have a decimal point.
|
|
||||||
// The pattern must end with a percentage sign (%).
|
|
||||||
|
|
||||||
cy.wrap($stakePercentage).should(
|
|
||||||
'match',
|
|
||||||
/\b(?<!\.)(?:0+(?:\.0+)?%|(?:\d|\d{1,2}|100)(?:(?<!100)\.\d+)?)%/
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2001-STKE-011 2002-SINC-001 2002-SINC-002
|
|
||||||
it('Should be able to see epoch information', function () {
|
|
||||||
const epochTitle = 'h3';
|
|
||||||
const nextEpochInfo = 'p';
|
|
||||||
|
|
||||||
cy.get(epochCountDown).within(() => {
|
|
||||||
cy.get(epochTitle).should('not.be.empty');
|
|
||||||
cy.get(nextEpochInfo).should('contain.text', 'Next epoch');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
// 1002-STKE-020 1002-STKE-021 1002-STKE-022 1002-STKE-023 1002-STKE-024
|
||||||
|
describe(
|
||||||
|
'Should be able to see validator list from the staking page',
|
||||||
|
{ tags: '@regression' },
|
||||||
|
function () {
|
||||||
|
// 1002-STKE-050
|
||||||
|
it('Should be able to see validator names', function () {
|
||||||
|
cy.get('[col-id="validator"] > div > span')
|
||||||
|
.should('have.length.at.least', 1)
|
||||||
|
.each(($name) => {
|
||||||
|
cy.wrap($name).should('not.be.empty');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to see validator stake', function () {
|
||||||
|
cy.getByTestId('total-stake')
|
||||||
|
.should('have.length.at.least', 1)
|
||||||
|
.each(($stake) => {
|
||||||
|
cy.wrap($stake).should('not.be.empty');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to see validator stake tooltip', function () {
|
||||||
|
waitForBeginningOfEpoch();
|
||||||
|
cy.getByTestId('total-stake').first().realHover();
|
||||||
|
|
||||||
|
cy.get(stakedByOperatorToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.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: 3,000.00');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to see validator normalised voting power', function () {
|
||||||
|
cy.getByTestId('normalised-voting-power')
|
||||||
|
.should('have.length.at.least', 1)
|
||||||
|
.each(($vPower) => {
|
||||||
|
cy.wrap($vPower).should('not.be.empty');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to see validator normalised voting power tooltip', function () {
|
||||||
|
waitForBeginningOfEpoch();
|
||||||
|
cy.getByTestId('normalised-voting-power').first().realHover();
|
||||||
|
|
||||||
|
cy.get(unnormalisedVotingPowerToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Unnormalised voting power: 20.00%');
|
||||||
|
cy.get(normalisedVotingPowerToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Normalised voting power: 50.00%');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2002-SINC-018
|
||||||
|
it('Should be able to see validator total penalties', function () {
|
||||||
|
cy.getByTestId('total-penalty')
|
||||||
|
.should('have.length.at.least', 1)
|
||||||
|
.each(($penalties) => {
|
||||||
|
cy.wrap($penalties).should('contain.text', '0%');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to see validator penalties tooltip', function () {
|
||||||
|
waitForBeginningOfEpoch();
|
||||||
|
cy.getByTestId('total-penalty').realHover();
|
||||||
|
|
||||||
|
cy.get(performancePenaltyToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Performance penalty: 0.00%');
|
||||||
|
cy.get(overstakedPenaltyToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Overstaked penalty: 60.00%'); // value not asserted due to #2886
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to see validator pending stake', function () {
|
||||||
|
cy.getByTestId('total-pending-stake')
|
||||||
|
.should('have.length.at.least', 1)
|
||||||
|
.each(($pendingStake) => {
|
||||||
|
cy.wrap($pendingStake).should('contain.text', '0.00');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to see multisig error', function () {
|
||||||
|
cy.mockGQL((req) => {
|
||||||
|
aliasGQLQuery(req, 'PreviousEpoch', previousEpochData);
|
||||||
|
});
|
||||||
|
waitForBeginningOfEpoch();
|
||||||
|
cy.getByTestId('total-penalty').first().realHover();
|
||||||
|
cy.get(multisigPenaltyToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Multisig penalty: 100%');
|
||||||
|
|
||||||
|
cy.getByTestId('total-penalty').eq(1).realHover();
|
||||||
|
cy.get(multisigPenaltyToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Multisig penalty: 100%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 1002-STKE-050
|
||||||
|
describe(
|
||||||
|
'Should be able to see static information about a validator',
|
||||||
|
{ tags: '@smoke' },
|
||||||
|
function () {
|
||||||
|
before('connect wallets and click on validator', function () {
|
||||||
|
cy.connectVegaWallet();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1002-STKE-006
|
||||||
|
it('Should be able to see validator name', function () {
|
||||||
|
cy.get(validatorTitle).should('not.be.empty');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1002-STKE-007
|
||||||
|
it('Should be able to see validator id', function () {
|
||||||
|
cy.get(validatorId).should('not.be.empty');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1002-STKE-008
|
||||||
|
it('Should be able to see validator public key', function () {
|
||||||
|
cy.get(validatorPubKey).should('not.be.empty');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1002-STKE-010
|
||||||
|
it('Should be able to see Ethereum address', function () {
|
||||||
|
cy.get(ethAddressLink).should('not.be.empty').and('have.attr', 'href');
|
||||||
|
});
|
||||||
|
// TODO validators missing url for more information about them 1002-STKE-09
|
||||||
|
|
||||||
|
it('Should be able to see validator status', function () {
|
||||||
|
cy.get(validatorStatus).should('have.text', 'Consensus');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1002-STKE-012
|
||||||
|
it('Should be able to see total stake', function () {
|
||||||
|
cy.get(totalStake).invoke('text').should('match', stakeNumberRegex);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to see pending stake', function () {
|
||||||
|
cy.get(pendingStake).invoke('text').should('match', stakeNumberRegex);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to see staked by operator', function () {
|
||||||
|
cy.get(stakedByOperator)
|
||||||
|
.invoke('text')
|
||||||
|
.should('match', stakeNumberRegex);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to see staked by delegates', function () {
|
||||||
|
cy.get(stakedByDelegates)
|
||||||
|
.invoke('text')
|
||||||
|
.should('match', stakeNumberRegex);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1002-STKE-051
|
||||||
|
it('Should be able to see stake share in percentage', function () {
|
||||||
|
cy.get(stakeShare)
|
||||||
|
.invoke('text')
|
||||||
|
.then(($stakePercentage) => {
|
||||||
|
// The pattern must start at a word boundary (\b).
|
||||||
|
// The pattern cannot be immediately preceded by a dot ((?<!\.)).
|
||||||
|
// The pattern can be one of the following:
|
||||||
|
// A percentage value of zero (0%), or
|
||||||
|
// A non-zero percentage value that can be:
|
||||||
|
// A single digit (\d) between 0 and 9, or
|
||||||
|
// A two-digit number between 0 and 99 (\d{1,2}), or
|
||||||
|
// The number 100.
|
||||||
|
// The pattern can optionally include a decimal point and one or more digits after the decimal point ((?:(?<!100)\.\d+)?). However, if the number is 100, it cannot have a decimal point.
|
||||||
|
// The pattern must end with a percentage sign (%).
|
||||||
|
|
||||||
|
cy.wrap($stakePercentage).should(
|
||||||
|
'match',
|
||||||
|
/\b(?<!\.)(?:0+(?:\.0+)?%|(?:\d|\d{1,2}|100)(?:(?<!100)\.\d+)?)%/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1002-STKE-011 2002-SINC-001 2002-SINC-002
|
||||||
|
it('Should be able to see epoch information', function () {
|
||||||
|
const epochTitle = 'h3';
|
||||||
|
const nextEpochInfo = 'p';
|
||||||
|
|
||||||
|
cy.get(epochCountDown).within(() => {
|
||||||
|
cy.get(epochTitle).should('not.be.empty');
|
||||||
|
cy.get(nextEpochInfo).should('contain.text', 'Next epoch');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { truncateByChars } from '@vegaprotocol/utils';
|
import { truncateByChars } from '@vegaprotocol/utils';
|
||||||
import { waitForSpinner } from '../../support/common.functions';
|
import { waitForSpinner } from '../../support/common.functions';
|
||||||
import { vegaWalletTeardown } from '../../support/wallet-teardown.functions';
|
import {
|
||||||
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions';
|
vegaWalletFaucetAssetsWithoutCheck,
|
||||||
|
vegaWalletTeardown,
|
||||||
|
} from '../../support/wallet-functions';
|
||||||
|
|
||||||
const walletContainer = 'aside [data-testid="vega-wallet"]';
|
const walletContainer = 'aside [data-testid="vega-wallet"]';
|
||||||
const walletHeader = '[data-testid="wallet-header"] h1';
|
const walletHeader = '[data-testid="wallet-header"] h1';
|
||||||
@@ -285,28 +287,28 @@ context(
|
|||||||
name: 'USDC (fake)',
|
name: 'USDC (fake)',
|
||||||
symbol: 'fUSDC',
|
symbol: 'fUSDC',
|
||||||
amount: '1000000',
|
amount: '1000000',
|
||||||
expectedAmount: '10.00',
|
expectedAmount: 10.0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '8566db7257222b5b7ef2886394ad28b938b28680a54a169bbc795027b89d6665',
|
id: '8566db7257222b5b7ef2886394ad28b938b28680a54a169bbc795027b89d6665',
|
||||||
name: 'DAI (fake)',
|
name: 'DAI (fake)',
|
||||||
symbol: 'fDAI',
|
symbol: 'fDAI',
|
||||||
amount: '200000',
|
amount: '200000',
|
||||||
expectedAmount: '2.00',
|
expectedAmount: 2.0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '73174a6fb1d5802ba0ac7bd7ab79e0a3a4837b262de0a4e80815a55442692bd0',
|
id: '73174a6fb1d5802ba0ac7bd7ab79e0a3a4837b262de0a4e80815a55442692bd0',
|
||||||
name: 'BTC (fake)',
|
name: 'BTC (fake)',
|
||||||
symbol: 'fBTC',
|
symbol: 'fBTC',
|
||||||
amount: '600000',
|
amount: '600000',
|
||||||
expectedAmount: '6.00',
|
expectedAmount: 6.0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'e02d4c15d790d1d2dffaf2dcd1cf06a1fe656656cf4ed18c8ce99f9e83643567',
|
id: 'e02d4c15d790d1d2dffaf2dcd1cf06a1fe656656cf4ed18c8ce99f9e83643567',
|
||||||
name: 'EURO (fake)',
|
name: 'EURO (fake)',
|
||||||
symbol: 'fEURO',
|
symbol: 'fEURO',
|
||||||
amount: '800000',
|
amount: '800000',
|
||||||
expectedAmount: '8.00',
|
expectedAmount: 8.0,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -317,12 +319,6 @@ context(
|
|||||||
cy.reload();
|
cy.reload();
|
||||||
waitForSpinner();
|
waitForSpinner();
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.get(walletContainer).within(() => {
|
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
|
||||||
'have.length.at.least',
|
|
||||||
5
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const { name, symbol, expectedAmount } of assets) {
|
for (const { name, symbol, expectedAmount } of assets) {
|
||||||
@@ -336,9 +332,10 @@ context(
|
|||||||
.contains(name)
|
.contains(name)
|
||||||
.parent()
|
.parent()
|
||||||
.siblings()
|
.siblings()
|
||||||
.invoke('text')
|
.then((elementAmount) => {
|
||||||
.then(parseFloat)
|
const displayedAmount = parseFloat(elementAmount.text());
|
||||||
.should('be.gte', parseFloat(expectedAmount));
|
expect(displayedAmount).be.gte(expectedAmount);
|
||||||
|
});
|
||||||
|
|
||||||
cy.get(vegaWalletCurrencyTitle)
|
cy.get(vegaWalletCurrencyTitle)
|
||||||
.contains(name)
|
.contains(name)
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
import { stakingPageDisassociateAllTokens } from './staking.functions';
|
||||||
|
|
||||||
const tokenDropDown = 'state-trigger';
|
const tokenDropDown = 'state-trigger';
|
||||||
const txTimeout = Cypress.env('txTimeout');
|
const txTimeout = Cypress.env('txTimeout');
|
||||||
|
|
||||||
export enum navigation {
|
export enum navigation {
|
||||||
section = 'nav',
|
section = 'nav',
|
||||||
|
home = '[href="/"]',
|
||||||
vesting = '[href="/token/redeem"]',
|
vesting = '[href="/token/redeem"]',
|
||||||
validators = '[href="/validators"]',
|
validators = '[href="/validators"]',
|
||||||
rewards = '[href="/rewards"]',
|
rewards = '[href="/rewards"]',
|
||||||
@@ -18,6 +21,7 @@ export function convertTokenValueToNumber(subject: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const topLevelRoutes = [
|
const topLevelRoutes = [
|
||||||
|
navigation.home,
|
||||||
navigation.proposals,
|
navigation.proposals,
|
||||||
navigation.validators,
|
navigation.validators,
|
||||||
navigation.rewards,
|
navigation.rewards,
|
||||||
@@ -33,7 +37,7 @@ export function navigateTo(page: navigation) {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return cy.get(navigation.section, { timeout: 10000 }).within(() => {
|
return cy.get(navigation.section, { timeout: 10000 }).within(() => {
|
||||||
cy.get(page).eq(0).click();
|
cy.get(page).eq(0).click({ force: true });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,3 +101,25 @@ export function turnTelemetryOff() {
|
|||||||
win.localStorage.setItem('vega_telemetry_on', 'false')
|
win.localStorage.setItem('vega_telemetry_on', 'false')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function dissociateFromSecondWalletKey() {
|
||||||
|
const secondWalletKey = Cypress.env('vegaWalletPublicKey2Short');
|
||||||
|
cy.getByTestId('vega-in-wallet')
|
||||||
|
.first()
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId('eth-wallet-associated-balances')
|
||||||
|
.last()
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId('associated-key')
|
||||||
|
.invoke('text')
|
||||||
|
.as('associatedPubKey');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
cy.get('@associatedPubKey').then((associatedPubKey) => {
|
||||||
|
if (associatedPubKey == secondWalletKey) {
|
||||||
|
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
|
||||||
|
cy.get('[data-testid="select-keypair-button"]').eq(0).click();
|
||||||
|
stakingPageDisassociateAllTokens();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -59,11 +59,11 @@ export function submitUniqueRawProposal(proposalFields: {
|
|||||||
submit?: boolean;
|
submit?: boolean;
|
||||||
}) {
|
}) {
|
||||||
goToMakeNewProposal(governanceProposalType.RAW);
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
let proposalBodyPath = '/proposals/raw.json';
|
let proposalBodyPath = 'src/fixtures/proposals/raw.json';
|
||||||
if (proposalFields.proposalBody) {
|
if (proposalFields.proposalBody) {
|
||||||
proposalBodyPath = proposalFields.proposalBody;
|
proposalBodyPath = proposalFields.proposalBody;
|
||||||
}
|
}
|
||||||
cy.fixture(proposalBodyPath).then((rawProposal) => {
|
cy.readFile(proposalBodyPath).then((rawProposal) => {
|
||||||
if (proposalFields.proposalTitle) {
|
if (proposalFields.proposalTitle) {
|
||||||
rawProposal.rationale.title = proposalFields.proposalTitle;
|
rawProposal.rationale.title = proposalFields.proposalTitle;
|
||||||
cy.wrap(proposalFields.proposalTitle).as('proposalTitle');
|
cy.wrap(proposalFields.proposalTitle).as('proposalTitle');
|
||||||
@@ -73,7 +73,10 @@ export function submitUniqueRawProposal(proposalFields: {
|
|||||||
}
|
}
|
||||||
if (proposalFields.closingTimestamp) {
|
if (proposalFields.closingTimestamp) {
|
||||||
rawProposal.terms.closingTimestamp = proposalFields.closingTimestamp;
|
rawProposal.terms.closingTimestamp = proposalFields.closingTimestamp;
|
||||||
} else {
|
} else if (
|
||||||
|
!proposalFields.closingTimestamp &&
|
||||||
|
!proposalFields.proposalBody
|
||||||
|
) {
|
||||||
const minTimeStamp = createTenDigitUnixTimeStampForSpecifiedDays(2);
|
const minTimeStamp = createTenDigitUnixTimeStampForSpecifiedDays(2);
|
||||||
rawProposal.terms.closingTimestamp = minTimeStamp;
|
rawProposal.terms.closingTimestamp = minTimeStamp;
|
||||||
}
|
}
|
||||||
@@ -106,7 +109,7 @@ export function enterUniqueFreeFormProposalBody(
|
|||||||
'this is a e2e freeform proposal description'
|
'this is a e2e freeform proposal description'
|
||||||
);
|
);
|
||||||
cy.get(proposalVoteDeadline).clear().click().type(timestamp);
|
cy.get(proposalVoteDeadline).clear().click().type(timestamp);
|
||||||
cy.getByTestId('proposal-submit').should('be.visible').click();
|
cy.getByTestId('proposal-download-json').should('be.visible').click();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProposalFromTitle(proposalTitle: string) {
|
export function getProposalFromTitle(proposalTitle: string) {
|
||||||
@@ -188,6 +191,7 @@ export function goToMakeNewProposal(proposalType: governanceProposalType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3001-VOTE-013 3001-VOTE-014
|
||||||
export function waitForProposalSubmitted() {
|
export function waitForProposalSubmitted() {
|
||||||
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
||||||
'be.visible'
|
'be.visible'
|
||||||
@@ -222,6 +226,23 @@ export function createFreeformProposal(proposalTitle: string) {
|
|||||||
navigateTo(navigation.proposals);
|
navigateTo(navigation.proposals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getDownloadedProposalJsonPath(proposalType: string) {
|
||||||
|
const downloadPath = './cypress/downloads/';
|
||||||
|
const filepath = downloadPath + proposalType + getFormattedTime() + '.json';
|
||||||
|
return filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFormattedTime() {
|
||||||
|
const now = new Date();
|
||||||
|
const day = now.getDate().toString().padStart(2, '0');
|
||||||
|
const month = now.toLocaleString('en-US', { month: 'short' });
|
||||||
|
const year = now.getFullYear().toString();
|
||||||
|
const hours = now.getHours().toString().padStart(2, '0');
|
||||||
|
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||||||
|
|
||||||
|
return `${day}-${month}-${year}-${hours}-${minutes}`;
|
||||||
|
}
|
||||||
|
|
||||||
export enum governanceProposalType {
|
export enum governanceProposalType {
|
||||||
NETWORK_PARAMETER = 'Network parameter',
|
NETWORK_PARAMETER = 'Network parameter',
|
||||||
NEW_MARKET = 'New market',
|
NEW_MARKET = 'New market',
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import './common.functions.ts';
|
|||||||
import './staking.functions.ts';
|
import './staking.functions.ts';
|
||||||
import './governance.functions.ts';
|
import './governance.functions.ts';
|
||||||
import './wallet-eth.functions.ts';
|
import './wallet-eth.functions.ts';
|
||||||
import './wallet-teardown.functions.ts';
|
import './wallet-functions.ts';
|
||||||
import './wallet-vega.functions.ts';
|
|
||||||
import './proposal.functions.ts';
|
import './proposal.functions.ts';
|
||||||
import 'cypress-mochawesome-reporter/register';
|
import 'cypress-mochawesome-reporter/register';
|
||||||
import registerCypressGrep from '@cypress/grep';
|
import registerCypressGrep from '@cypress/grep';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { closeDialog } from './common.functions';
|
import { closeDialog } from './common.functions';
|
||||||
import { vegaWalletTeardown } from './wallet-teardown.functions';
|
import { vegaWalletTeardown } from './wallet-functions';
|
||||||
|
|
||||||
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
|
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
|
||||||
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
|
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
|
||||||
@@ -221,7 +221,7 @@ export function ensureSpecifiedUnstakedTokensAreAssociated(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function closeStakingDialog() {
|
export function closeStakingDialog() {
|
||||||
cy.getByTestId('dialog-title').should(
|
cy.getByTestId('dialog-title', txTimeout).should(
|
||||||
'contain.text',
|
'contain.text',
|
||||||
'At the beginning of the next epoch'
|
'At the beginning of the next epoch'
|
||||||
);
|
);
|
||||||
@@ -236,8 +236,8 @@ export function validateWalletCurrency(
|
|||||||
currencyTitle: string,
|
currencyTitle: string,
|
||||||
expectedAmount: string
|
expectedAmount: string
|
||||||
) {
|
) {
|
||||||
cy.get("[data-testid='currency-title']")
|
cy.get("[data-testid='currency-title']", txTimeout)
|
||||||
.contains(currencyTitle)
|
.contains(currencyTitle, txTimeout)
|
||||||
.parent()
|
.parent()
|
||||||
.parent()
|
.parent()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const capsuleWalletConnectButton = '[data-testid="web3-connector-Unknown"]';
|
|||||||
|
|
||||||
export function ethereumWalletConnect() {
|
export function ethereumWalletConnect() {
|
||||||
cy.highlight('Connecting Eth Wallet');
|
cy.highlight('Connecting Eth Wallet');
|
||||||
cy.get(connectToEthButton).within(() => {
|
cy.get(connectToEthButton, { timeout: 60000 }).within(() => {
|
||||||
cy.contains('Connect Ethereum wallet to associate $VEGA')
|
cy.contains('Connect Ethereum wallet to associate $VEGA')
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.click();
|
.click();
|
||||||
|
|||||||
+49
-34
@@ -19,7 +19,7 @@ const ethStakingBridgeContractAddress = Cypress.env(
|
|||||||
);
|
);
|
||||||
const ethProviderUrl = Cypress.env('ethProviderUrl');
|
const ethProviderUrl = Cypress.env('ethProviderUrl');
|
||||||
const getAccount = (number = 0) => `m/44'/60'/0'/0/${number}`;
|
const getAccount = (number = 0) => `m/44'/60'/0'/0/${number}`;
|
||||||
const transactionTimeout = 100000;
|
const transactionTimeout = { timeout: 100000, log: false };
|
||||||
const Erc20BridgeAddress = '0x9708FF7510D4A7B9541e1699d15b53Ecb1AFDc54';
|
const Erc20BridgeAddress = '0x9708FF7510D4A7B9541e1699d15b53Ecb1AFDc54';
|
||||||
|
|
||||||
const provider = new ethers.providers.JsonRpcProvider({ url: ethProviderUrl });
|
const provider = new ethers.providers.JsonRpcProvider({ url: ethProviderUrl });
|
||||||
@@ -43,10 +43,7 @@ export async function depositAsset(
|
|||||||
const faucet = new Token(assetEthAddress, signer);
|
const faucet = new Token(assetEthAddress, signer);
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
faucet.approve(Erc20BridgeAddress, amount + '0'.repeat(decimalPlaces + 1)),
|
faucet.approve(Erc20BridgeAddress, amount + '0'.repeat(decimalPlaces + 1)),
|
||||||
{
|
transactionTimeout
|
||||||
timeout: transactionTimeout,
|
|
||||||
log: false,
|
|
||||||
}
|
|
||||||
).then(() => {
|
).then(() => {
|
||||||
const collateralBridge = new CollateralBridge(Erc20BridgeAddress, signer);
|
const collateralBridge = new CollateralBridge(Erc20BridgeAddress, signer);
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
@@ -55,7 +52,7 @@ export async function depositAsset(
|
|||||||
amount + '0'.repeat(decimalPlaces),
|
amount + '0'.repeat(decimalPlaces),
|
||||||
'0x' + vegaWalletPubKey
|
'0x' + vegaWalletPubKey
|
||||||
),
|
),
|
||||||
{ timeout: transactionTimeout, log: false }
|
transactionTimeout
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -79,13 +76,13 @@ export async function vegaWalletTeardown() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
cy.get(vegaWalletContainer).within(() => {
|
cy.get(vegaWalletContainer).within(() => {
|
||||||
cy.get(associatedAmountInWallet, {
|
cy.get(associatedAmountInWallet, transactionTimeout).should(
|
||||||
timeout: transactionTimeout,
|
'have.length',
|
||||||
})
|
1
|
||||||
.should('have.length', 1, { timeout: transactionTimeout })
|
);
|
||||||
.contains('0.00', {
|
cy.get(associatedAmountInWallet)
|
||||||
timeout: transactionTimeout,
|
.first(transactionTimeout)
|
||||||
});
|
.should('have.text', '0.00');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -109,7 +106,7 @@ async function vegaWalletTeardownStaking(stakingBridgeContract: StakingBridge) {
|
|||||||
cy.highlight('Tearing down staking tokens from vega wallet if present');
|
cy.highlight('Tearing down staking tokens from vega wallet if present');
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
stakingBridgeContract.stake_balance(ethWalletPubKey, vegaWalletPubKey),
|
stakingBridgeContract.stake_balance(ethWalletPubKey, vegaWalletPubKey),
|
||||||
{ timeout: transactionTimeout }
|
transactionTimeout
|
||||||
).then((stakeBalance) => {
|
).then((stakeBalance) => {
|
||||||
if (Number(stakeBalance) != 0) {
|
if (Number(stakeBalance) != 0) {
|
||||||
cy.get(vegaWalletContainer).within(() => {
|
cy.get(vegaWalletContainer).within(() => {
|
||||||
@@ -122,31 +119,25 @@ async function vegaWalletTeardownStaking(stakingBridgeContract: StakingBridge) {
|
|||||||
String(stakeBalance),
|
String(stakeBalance),
|
||||||
vegaWalletPubKey
|
vegaWalletPubKey
|
||||||
),
|
),
|
||||||
{ timeout: transactionTimeout }
|
transactionTimeout
|
||||||
);
|
);
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
vestingContract.stake_balance(ethWalletPubKey, vegaWalletPubKey),
|
vestingContract.stake_balance(ethWalletPubKey, vegaWalletPubKey),
|
||||||
{
|
transactionTimeout
|
||||||
timeout: transactionTimeout,
|
|
||||||
log: false,
|
|
||||||
}
|
|
||||||
).then((vestingAmount) => {
|
).then((vestingAmount) => {
|
||||||
if (Number(vestingAmount) != 0) {
|
if (Number(vestingAmount) != 0) {
|
||||||
cy.contains('Associated', {
|
cy.contains('Associated', transactionTimeout)
|
||||||
timeout: transactionTimeout,
|
|
||||||
})
|
|
||||||
.parent()
|
.parent()
|
||||||
.parent()
|
.parent()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId('currency-value', {
|
cy.getByTestId('currency-value', transactionTimeout)
|
||||||
timeout: transactionTimeout,
|
.first()
|
||||||
})
|
|
||||||
.should('have.length', 1)
|
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.as('displayedAmount');
|
.as('displayedAmount');
|
||||||
cy.get('@displayedAmount', {
|
cy.get('@displayedAmount', transactionTimeout).should(
|
||||||
timeout: transactionTimeout,
|
'not.eq',
|
||||||
}).should('not.eq', $associatedAmount);
|
$associatedAmount
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -158,14 +149,14 @@ async function vegaWalletTeardownStaking(stakingBridgeContract: StakingBridge) {
|
|||||||
|
|
||||||
async function vegaWalletTeardownVesting(vestingContract: TokenVesting) {
|
async function vegaWalletTeardownVesting(vestingContract: TokenVesting) {
|
||||||
cy.highlight('Tearing down vesting tokens from vega wallet if present');
|
cy.highlight('Tearing down vesting tokens from vega wallet if present');
|
||||||
cy.wrap(vestingContract.stake_balance(ethWalletPubKey, vegaWalletPubKey), {
|
cy.wrap(
|
||||||
timeout: transactionTimeout,
|
vestingContract.stake_balance(ethWalletPubKey, vegaWalletPubKey),
|
||||||
log: false,
|
transactionTimeout
|
||||||
}).then((vestingAmount) => {
|
).then((vestingAmount) => {
|
||||||
if (Number(vestingAmount) != 0) {
|
if (Number(vestingAmount) != 0) {
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
vestingContract.remove_stake(String(vestingAmount), vegaWalletPubKey),
|
vestingContract.remove_stake(String(vestingAmount), vegaWalletPubKey),
|
||||||
{ timeout: transactionTimeout }
|
transactionTimeout
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -182,3 +173,27 @@ export async function vegaWalletDisassociate(amount: string) {
|
|||||||
amount = amount + '0'.repeat(18);
|
amount = amount + '0'.repeat(18);
|
||||||
stakingBridgeContract.remove_stake(amount, vegaWalletPubKey);
|
stakingBridgeContract.remove_stake(amount, vegaWalletPubKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function vegaWalletFaucetAssetsWithoutCheck(
|
||||||
|
asset: string,
|
||||||
|
amount: string,
|
||||||
|
vegaWalletPublicKey: string
|
||||||
|
) {
|
||||||
|
cy.highlight(`Topping up vega wallet with ${asset}, amount: ${amount}`);
|
||||||
|
cy.exec(
|
||||||
|
`curl -X POST -d '{"amount": "${amount}", "asset": "${asset}", "party": "${vegaWalletPublicKey}"}' http://localhost:1790/api/v1/mint`
|
||||||
|
)
|
||||||
|
.its('stdout')
|
||||||
|
.then((response) => {
|
||||||
|
assert.include(
|
||||||
|
response,
|
||||||
|
`"success":true`,
|
||||||
|
'Ensuring curl command was successfully undertaken'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function switchVegaWalletPubKey() {
|
||||||
|
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
|
||||||
|
cy.get('[data-testid="select-keypair-button"]').eq(0).click();
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
export function vegaWalletFaucetAssetsWithoutCheck(
|
|
||||||
asset: string,
|
|
||||||
amount: string,
|
|
||||||
vegaWalletPublicKey: string
|
|
||||||
) {
|
|
||||||
cy.highlight(`Topping up vega wallet with ${asset}, amount: ${amount}`);
|
|
||||||
cy.exec(
|
|
||||||
`curl -X POST -d '{"amount": "${amount}", "asset": "${asset}", "party": "${vegaWalletPublicKey}"}' http://localhost:1790/api/v1/mint`
|
|
||||||
)
|
|
||||||
.its('stdout')
|
|
||||||
.then((response) => {
|
|
||||||
assert.include(
|
|
||||||
response,
|
|
||||||
`"success":true`,
|
|
||||||
'Ensuring curl command was successfully undertaken'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@ NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","TESTNET":"https:/
|
|||||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||||
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
|
NX_VEGA_EXPLORER_URL=#
|
||||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||||
NX_DELEGATIONS_PAGINATION=50
|
NX_DELEGATIONS_PAGINATION=50
|
||||||
NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
|
NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ NX_VEGA_ENV=MAINNET
|
|||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_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_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz"}'
|
||||||
NX_ETHEREUM_PROVIDER_URL=https://eth-mainnet.gateway.pokt.network/v1/lb/6684b914570bbfa533ba9324
|
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/3ba145ccc2884bcd91213d8dc989ca76
|
||||||
NX_ETHERSCAN_URL=https://etherscan.io
|
NX_ETHERSCAN_URL=https://etherscan.io
|
||||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","TESTNET":"https:/
|
|||||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||||
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
|
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
||||||
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_REST_URL=https://api-validators-testnet.vega.rocks/api/v2/
|
NX_VEGA_REST_URL=https://api-validators-testnet.vega.rocks/api/v2/
|
||||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './multisig-incorrect-notice';
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||||
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
|
import { MultisigIncorrectNotice } from './multisig-incorrect-notice';
|
||||||
|
|
||||||
|
jest.mock('@vegaprotocol/web3', () => ({
|
||||||
|
useEthereumConfig: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('@vegaprotocol/environment', () => ({
|
||||||
|
useEnvironment: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('MultisigIncorrectNotice', () => {
|
||||||
|
it('renders correctly when config is provided', () => {
|
||||||
|
(useEthereumConfig as jest.Mock).mockReturnValue({
|
||||||
|
config: {
|
||||||
|
multisig_control_contract: {
|
||||||
|
address: '0x1234',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
(useEnvironment as unknown as jest.Mock).mockReturnValue({
|
||||||
|
ETHERSCAN_URL: 'https://etherscan.io',
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<MultisigIncorrectNotice />);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('multisig-contract-link')).toHaveAttribute(
|
||||||
|
'href',
|
||||||
|
'https://etherscan.io/address/0x1234'
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('multisig-contract-link')).toHaveAttribute(
|
||||||
|
'title',
|
||||||
|
'0x1234'
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
screen.getByTestId('multisig-validators-learn-more')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not render when config is not provided', () => {
|
||||||
|
(useEthereumConfig as jest.Mock).mockReturnValue({
|
||||||
|
config: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = render(<MultisigIncorrectNotice />);
|
||||||
|
|
||||||
|
expect(container.firstChild).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Callout, Intent, Link } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||||
|
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
||||||
|
import type { EthereumConfig } from '@vegaprotocol/web3';
|
||||||
|
|
||||||
|
export const MultisigIncorrectNotice = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { config } = useEthereumConfig();
|
||||||
|
const { ETHERSCAN_URL } = useEnvironment();
|
||||||
|
|
||||||
|
if (!config) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const contract = config[
|
||||||
|
'multisig_control_contract' as keyof EthereumConfig
|
||||||
|
] as {
|
||||||
|
address: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-10">
|
||||||
|
<Callout intent={Intent.Warning}>
|
||||||
|
<div>
|
||||||
|
<Link
|
||||||
|
title={contract.address}
|
||||||
|
href={`${ETHERSCAN_URL}/address/${contract.address}`}
|
||||||
|
target="_blank"
|
||||||
|
data-testid="multisig-contract-link"
|
||||||
|
>
|
||||||
|
{t('multisigContractLink')}
|
||||||
|
</Link>{' '}
|
||||||
|
{t('multisigContractIncorrect')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-2">
|
||||||
|
<Link
|
||||||
|
href={DocsLinks?.VALIDATOR_SCORES_REWARDS}
|
||||||
|
target="_blank"
|
||||||
|
data-testid="multisig-validators-learn-more"
|
||||||
|
>
|
||||||
|
{t('learnMore')}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</Callout>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -3,32 +3,32 @@ import { usePendingBalancesStore } from './use-pending-balances-manager';
|
|||||||
import type { Contract } from 'ethers';
|
import type { Contract } from 'ethers';
|
||||||
import { useListenForPendingEthEvents } from './use-listen-for-pending-eth-events';
|
import { useListenForPendingEthEvents } from './use-listen-for-pending-eth-events';
|
||||||
import { prepend0x } from '@vegaprotocol/smart-contracts';
|
import { prepend0x } from '@vegaprotocol/smart-contracts';
|
||||||
|
import { useWeb3React } from '@web3-react/core';
|
||||||
|
|
||||||
export const useListenForStakingEvents = (
|
export const useListenForStakingEvents = (
|
||||||
contract: Contract | undefined,
|
contract: Contract | undefined,
|
||||||
vegaPublicKey: string | null,
|
vegaPublicKey: string | null,
|
||||||
numberOfConfirmations: number
|
numberOfConfirmations: number
|
||||||
) => {
|
) => {
|
||||||
|
const { account } = useWeb3React();
|
||||||
const { addPendingTxs, removePendingTx, resetPendingTxs } =
|
const { addPendingTxs, removePendingTx, resetPendingTxs } =
|
||||||
usePendingBalancesStore((state) => ({
|
usePendingBalancesStore((state) => ({
|
||||||
addPendingTxs: state.addPendingTxs,
|
addPendingTxs: state.addPendingTxs,
|
||||||
removePendingTx: state.removePendingTx,
|
removePendingTx: state.removePendingTx,
|
||||||
resetPendingTxs: state.resetPendingTxs,
|
resetPendingTxs: state.resetPendingTxs,
|
||||||
}));
|
}));
|
||||||
const addFilter = useMemo(
|
const addFilter = useMemo(() => {
|
||||||
() =>
|
if (!account || !vegaPublicKey || !contract) return null;
|
||||||
vegaPublicKey && contract
|
return contract.filters.Stake_Deposited(
|
||||||
? contract.filters.Stake_Deposited(null, null, prepend0x(vegaPublicKey))
|
null,
|
||||||
: null,
|
null,
|
||||||
[contract, vegaPublicKey]
|
prepend0x(vegaPublicKey)
|
||||||
);
|
);
|
||||||
const removeFilter = useMemo(
|
}, [contract, vegaPublicKey, account]);
|
||||||
() =>
|
const removeFilter = useMemo(() => {
|
||||||
vegaPublicKey && contract
|
if (!account || !vegaPublicKey || !contract) return null;
|
||||||
? contract.filters.Stake_Removed(null, null, prepend0x(vegaPublicKey))
|
return contract.filters.Stake_Removed(null, null, prepend0x(vegaPublicKey));
|
||||||
: null,
|
}, [contract, vegaPublicKey, account]);
|
||||||
[contract, vegaPublicKey]
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen for all add stake events
|
* Listen for all add stake events
|
||||||
|
|||||||
@@ -116,7 +116,7 @@
|
|||||||
"Showing tranches with <{{trancheMinimum}} VEGA, click to hide these tranches": "Showing tranches with ≤{{trancheMinimum}} $VEGA, click to hide these tranches",
|
"Showing tranches with <{{trancheMinimum}} VEGA, click to hide these tranches": "Showing tranches with ≤{{trancheMinimum}} $VEGA, click to hide these tranches",
|
||||||
"Not showing tranches with <{{trancheMinimum}} VEGA, click to show all tranches": "Not showing tranches with ≤{{trancheMinimum}} $VEGA, click to show all tranches",
|
"Not showing tranches with <{{trancheMinimum}} VEGA, click to show all tranches": "Not showing tranches with ≤{{trancheMinimum}} $VEGA, click to show all tranches",
|
||||||
"the holder": "the holder",
|
"the holder": "the holder",
|
||||||
"We couldn't seem to load your data.": "We couldn't seem to load your data.",
|
"Your data couldn't be loaded": "Your data couldn't be loaded",
|
||||||
"Vesting VEGA": "Vesting VEGA",
|
"Vesting VEGA": "Vesting VEGA",
|
||||||
"All the tokens in this tranche are locked and can not be redeemed yet.": "All the tokens in this tranche are locked and can not be redeemed yet.",
|
"All the tokens in this tranche are locked and can not be redeemed yet.": "All the tokens in this tranche are locked and can not be redeemed yet.",
|
||||||
"Redeem unlocked VEGA from tranche {{id}}": "Redeem unlocked $VEGA from tranche {{id}}",
|
"Redeem unlocked VEGA from tranche {{id}}": "Redeem unlocked $VEGA from tranche {{id}}",
|
||||||
@@ -596,6 +596,8 @@
|
|||||||
"noPercentage": "No percentage",
|
"noPercentage": "No percentage",
|
||||||
"proposalJson": "Full proposal JSON",
|
"proposalJson": "Full proposal JSON",
|
||||||
"proposalDetails": "Proposal details",
|
"proposalDetails": "Proposal details",
|
||||||
|
"marketSpecification": "Market specification",
|
||||||
|
"viewMarketJson": "View market JSON",
|
||||||
"proposalDescription": "Description",
|
"proposalDescription": "Description",
|
||||||
"currentlySetTo": "Currently expected to ",
|
"currentlySetTo": "Currently expected to ",
|
||||||
"currently": "currently",
|
"currently": "currently",
|
||||||
@@ -728,8 +730,12 @@
|
|||||||
"ThisWillSetEnactmentDeadlineTo": "This will set the enactment date to",
|
"ThisWillSetEnactmentDeadlineTo": "This will set the enactment date to",
|
||||||
"ThisWillSetValidationDeadlineTo": "This will set the validation deadline to",
|
"ThisWillSetValidationDeadlineTo": "This will set the validation deadline to",
|
||||||
"Hours": "hours",
|
"Hours": "hours",
|
||||||
"ThisWillAdd2MinutesToAllowTimeToConfirmInWallet": "Note: we add 2 minutes of extra time when you choose the minimum value. This gives you time to confirm the proposal in your wallet.",
|
"ThisWillAdd2MinutesToAllowTimeToConfirmInWallet": "Note: 2 minutes of extra time are added when you choose the minimum value. This gives you time to confirm the proposal in your wallet.",
|
||||||
"ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline": "Proposal will fail if enactment is earlier than the voting deadline",
|
"ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline": "The proposal will fail if enactment is earlier than the voting deadline",
|
||||||
|
"ProposalWillFailIfEnactmentIsBelowTheMinimumDeadline": "The proposal will fail if enactment deadline is below the minimum",
|
||||||
|
"ProposalWillFailIfVotingIsBelowTheMinimumDeadline": "The proposal will fail if voting deadline is below the minimum",
|
||||||
|
"ProposalWillFailIfEnactmentIsAboveTheMaximumDeadline": "The proposal will fail if enactment deadline is above the maximum",
|
||||||
|
"ProposalWillFailIfVotingIsAboveTheMaximumDeadline": "The proposal will fail if voting deadline is above the maximum",
|
||||||
"SelectAMarketToChange": "Select a market to change",
|
"SelectAMarketToChange": "Select a market to change",
|
||||||
"MarketName": "Market name",
|
"MarketName": "Market name",
|
||||||
"MarketCode": "Market code",
|
"MarketCode": "Market code",
|
||||||
@@ -780,6 +786,7 @@
|
|||||||
"performancePenalty": "Performance penalty",
|
"performancePenalty": "Performance penalty",
|
||||||
"overstaked": "Overstaked",
|
"overstaked": "Overstaked",
|
||||||
"overstakedPenalty": "Overstaked penalty",
|
"overstakedPenalty": "Overstaked penalty",
|
||||||
|
"multisigPenalty": "Multisig penalty",
|
||||||
"homeProposalsIntro": "Decisions on the Vega network are on-chain, with tokenholders creating proposals that other tokenholders vote to approve or reject. Network upgrades are proposed and approved by validators.",
|
"homeProposalsIntro": "Decisions on the Vega network are on-chain, with tokenholders creating proposals that other tokenholders vote to approve or reject. Network upgrades are proposed and approved by validators.",
|
||||||
"homeProposalsButtonText": "Browse, vote, and propose",
|
"homeProposalsButtonText": "Browse, vote, and propose",
|
||||||
"homeValidatorsIntro": "Vega runs on a delegated proof of stake blockchain, where validators earn fees for validating block transactions. Tokenholders can nominate validators by staking tokens to them.",
|
"homeValidatorsIntro": "Vega runs on a delegated proof of stake blockchain, where validators earn fees for validating block transactions. Tokenholders can nominate validators by staking tokens to them.",
|
||||||
@@ -821,5 +828,10 @@
|
|||||||
"disclaimer2": "The Vega Governance App is free, public and open source software. Software upgrades may contain bugs or security vulnerabilities that might result in loss of functionality.",
|
"disclaimer2": "The Vega Governance App is free, public and open source software. Software upgrades may contain bugs or security vulnerabilities that might result in loss of functionality.",
|
||||||
"disclaimer3": "The Vega Governance App uses data obtained from nodes on the Vega Blockchain. The developers of the Vega Governance App do not operate or run the Vega Blockchain or any other blockchain.",
|
"disclaimer3": "The Vega Governance App uses data obtained from nodes on the Vega Blockchain. The developers of the Vega Governance App do not operate or run the Vega Blockchain or any other blockchain.",
|
||||||
"disclaimer4": "The Vega Governance App is provided “as is”. The developers of the Vega Governance App make no representations or warranties of any kind, whether express or implied, statutory or otherwise regarding the Vega Governance App. They disclaim all warranties of merchantability, quality, fitness for purpose. They disclaim all warranties that the Vega Governance App is free of harmful components or errors.",
|
"disclaimer4": "The Vega Governance App is provided “as is”. The developers of the Vega Governance App make no representations or warranties of any kind, whether express or implied, statutory or otherwise regarding the Vega Governance App. They disclaim all warranties of merchantability, quality, fitness for purpose. They disclaim all warranties that the Vega Governance App is free of harmful components or errors.",
|
||||||
"disclaimer5": "No developer of the Vega Governance App accepts any responsibility for, or liability to users in connection with their use of the Vega Governance App."
|
"disclaimer5": "No developer of the Vega Governance App accepts any responsibility for, or liability to users in connection with their use of the Vega Governance App.",
|
||||||
|
"multisigContractLink": "Ethereum Multisig Contract",
|
||||||
|
"multisigContractIncorrect": "is incorrectly configured. Validator and delegator rewards will be penalised until this is resolved.",
|
||||||
|
"learnMore": "Learn more",
|
||||||
|
"AllValidators": "All validators",
|
||||||
|
"AllProposals": "All proposals"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
export const collapsibleToggleStyles = (toggleState: boolean) =>
|
||||||
|
classnames('mb-4 transition-transform ease-in-out duration-300', {
|
||||||
|
'rotate-180': toggleState,
|
||||||
|
});
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import {
|
||||||
|
getMultisigStatusInfo,
|
||||||
|
MultisigStatus,
|
||||||
|
} from './get-multisig-status-info';
|
||||||
|
import type { PreviousEpochQuery } from '../routes/staking/__generated__/PreviousEpoch';
|
||||||
|
|
||||||
|
const createNode = (id: string, multisigScore: string) => ({
|
||||||
|
node: {
|
||||||
|
id,
|
||||||
|
stakedTotal: '1000',
|
||||||
|
rewardScore: { multisigScore },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getMultisigStatus', () => {
|
||||||
|
it('should return MultisigStatus.noNodes when no nodes are present', () => {
|
||||||
|
const result = getMultisigStatusInfo({
|
||||||
|
epoch: { id: '1', validatorsConnection: { edges: [] } },
|
||||||
|
} as PreviousEpochQuery);
|
||||||
|
expect(result).toEqual({
|
||||||
|
multisigStatus: MultisigStatus.noNodes,
|
||||||
|
showMultisigStatusError: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return MultisigStatus.correct when all nodes have multisigScore of 1', () => {
|
||||||
|
const result = getMultisigStatusInfo({
|
||||||
|
epoch: {
|
||||||
|
id: '1',
|
||||||
|
validatorsConnection: {
|
||||||
|
edges: [createNode('1', '1'), createNode('2', '1')],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as PreviousEpochQuery);
|
||||||
|
expect(result).toEqual({
|
||||||
|
multisigStatus: MultisigStatus.correct,
|
||||||
|
showMultisigStatusError: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return MultisigStatus.nodeNeedsRemoving when all nodes have multisigScore of 0', () => {
|
||||||
|
const result = getMultisigStatusInfo({
|
||||||
|
epoch: {
|
||||||
|
id: '1',
|
||||||
|
validatorsConnection: {
|
||||||
|
edges: [createNode('1', '0'), createNode('2', '0')],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as PreviousEpochQuery);
|
||||||
|
expect(result).toEqual({
|
||||||
|
multisigStatus: MultisigStatus.nodeNeedsRemoving,
|
||||||
|
showMultisigStatusError: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return MultisigStatus.nodeNeedsAdding when some nodes have multisigScore of 0 and others have 1', () => {
|
||||||
|
const result = getMultisigStatusInfo({
|
||||||
|
epoch: {
|
||||||
|
id: '1',
|
||||||
|
validatorsConnection: {
|
||||||
|
edges: [createNode('1', '0'), createNode('2', '1')],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as PreviousEpochQuery);
|
||||||
|
expect(result).toEqual({
|
||||||
|
multisigStatus: MultisigStatus.nodeNeedsAdding,
|
||||||
|
showMultisigStatusError: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||||
|
import type { PreviousEpochQuery } from '../routes/staking/__generated__/PreviousEpoch';
|
||||||
|
|
||||||
|
export enum MultisigStatus {
|
||||||
|
'correct' = 'correct',
|
||||||
|
'nodeNeedsAdding' = 'nodeNeedsAdding',
|
||||||
|
'nodeNeedsRemoving' = 'nodeNeedsRemoving ',
|
||||||
|
'noNodes' = 'noNodes',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getMultisigStatusInfo = (
|
||||||
|
previousEpochData: PreviousEpochQuery
|
||||||
|
) => {
|
||||||
|
let status = MultisigStatus.noNodes;
|
||||||
|
|
||||||
|
const allNodesInPreviousEpoch = removePaginationWrapper(
|
||||||
|
previousEpochData?.epoch.validatorsConnection?.edges
|
||||||
|
);
|
||||||
|
|
||||||
|
const hasZero = allNodesInPreviousEpoch.some(
|
||||||
|
(node) => Number(node?.rewardScore?.multisigScore) === 0
|
||||||
|
);
|
||||||
|
const hasOne = allNodesInPreviousEpoch.some(
|
||||||
|
(node) => Number(node?.rewardScore?.multisigScore) === 1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hasZero && hasOne) {
|
||||||
|
// If any individual node has 0 it means that node is missing from the multisig and needs to be added
|
||||||
|
status = MultisigStatus.nodeNeedsAdding;
|
||||||
|
} else if (hasZero) {
|
||||||
|
// If all nodes have 0 it means there is an incorrect address in the multisig that needs to be removed
|
||||||
|
status = MultisigStatus.nodeNeedsRemoving;
|
||||||
|
} else if (allNodesInPreviousEpoch.length > 0) {
|
||||||
|
// If all nodes have 1 it means the multisig is correct
|
||||||
|
status = MultisigStatus.correct;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
showMultisigStatusError: status !== MultisigStatus.correct,
|
||||||
|
multisigStatus: status,
|
||||||
|
};
|
||||||
|
};
|
||||||
+2
-5
@@ -1,9 +1,9 @@
|
|||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import classnames from 'classnames';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Icon, RoundedWrapper } from '@vegaprotocol/ui-toolkit';
|
import { Icon, RoundedWrapper } from '@vegaprotocol/ui-toolkit';
|
||||||
import { SubHeading } from '../../../../components/heading';
|
import { SubHeading } from '../../../../components/heading';
|
||||||
|
import { collapsibleToggleStyles } from '../../../../lib/collapsible-toggle-styles';
|
||||||
|
|
||||||
export const ProposalDescription = ({
|
export const ProposalDescription = ({
|
||||||
description,
|
description,
|
||||||
@@ -12,9 +12,6 @@ export const ProposalDescription = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [showDescription, setShowDescription] = useState(false);
|
const [showDescription, setShowDescription] = useState(false);
|
||||||
const showDescriptionIconClasses = classnames('mb-4', {
|
|
||||||
'rotate-180': showDescription,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section data-testid="proposal-description">
|
<section data-testid="proposal-description">
|
||||||
@@ -24,7 +21,7 @@ export const ProposalDescription = ({
|
|||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<SubHeading title={t('proposalDescription')} />
|
<SubHeading title={t('proposalDescription')} />
|
||||||
<div className={showDescriptionIconClasses}>
|
<div className={collapsibleToggleStyles(showDescription)}>
|
||||||
<Icon name="chevron-down" size={8} />
|
<Icon name="chevron-down" size={8} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import classnames from 'classnames';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Icon, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
import { Icon, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||||
import { SubHeading } from '../../../../components/heading';
|
import { SubHeading } from '../../../../components/heading';
|
||||||
|
import { collapsibleToggleStyles } from '../../../../lib/collapsible-toggle-styles';
|
||||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
@@ -13,9 +13,6 @@ export const ProposalJson = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [showDetails, setShowDetails] = useState(false);
|
const [showDetails, setShowDetails] = useState(false);
|
||||||
const showDetailsIconClasses = classnames('mb-4', {
|
|
||||||
'rotate-180': showDetails,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section data-testid="proposal-json">
|
<section data-testid="proposal-json">
|
||||||
@@ -25,7 +22,7 @@ export const ProposalJson = ({
|
|||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<SubHeading title={t('proposalJson')} />
|
<SubHeading title={t('proposalJson')} />
|
||||||
<div className={showDetailsIconClasses}>
|
<div className={collapsibleToggleStyles(showDetails)}>
|
||||||
<Icon name="chevron-down" size={8} />
|
<Icon name="chevron-down" size={8} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './proposal-market-data';
|
||||||
+222
@@ -0,0 +1,222 @@
|
|||||||
|
import isEqual from 'lodash/isEqual';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import {
|
||||||
|
InstrumentInfoPanel,
|
||||||
|
KeyDetailsInfoPanel,
|
||||||
|
LiquidityMonitoringParametersInfoPanel,
|
||||||
|
LiquidityPriceRangeInfoPanel,
|
||||||
|
MetadataInfoPanel,
|
||||||
|
OracleInfoPanel,
|
||||||
|
PriceMonitoringBoundsInfoPanel,
|
||||||
|
RiskFactorsInfoPanel,
|
||||||
|
RiskModelInfoPanel,
|
||||||
|
RiskParametersInfoPanel,
|
||||||
|
SettlementAssetInfoPanel,
|
||||||
|
} from '@vegaprotocol/markets';
|
||||||
|
import {
|
||||||
|
Accordion,
|
||||||
|
AccordionItem,
|
||||||
|
Button,
|
||||||
|
CopyWithTooltip,
|
||||||
|
Dialog,
|
||||||
|
Icon,
|
||||||
|
SyntaxHighlighter,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { SubHeading } from '../../../../components/heading';
|
||||||
|
import { collapsibleToggleStyles } from '../../../../lib/collapsible-toggle-styles';
|
||||||
|
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||||
|
import type { DataSourceDefinition } from '@vegaprotocol/types';
|
||||||
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
type MarketDataDialogState = {
|
||||||
|
isOpen: boolean;
|
||||||
|
open: () => void;
|
||||||
|
close: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMarketDataDialogStore = create<MarketDataDialogState>(
|
||||||
|
(set) => ({
|
||||||
|
isOpen: false,
|
||||||
|
open: () => set({ isOpen: true }),
|
||||||
|
close: () => set({ isOpen: false }),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
export const ProposalMarketData = ({
|
||||||
|
marketData,
|
||||||
|
}: {
|
||||||
|
marketData: MarketInfoWithData;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { isOpen, open, close } = useMarketDataDialogStore();
|
||||||
|
const [showDetails, setShowDetails] = useState(false);
|
||||||
|
|
||||||
|
if (!marketData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settlementData = marketData.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
|
||||||
|
const terminationData = marketData.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
|
||||||
|
|
||||||
|
const getSigners = (data: DataSourceDefinition) => {
|
||||||
|
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||||
|
const signers = data.sourceType.sourceType.signers || [];
|
||||||
|
|
||||||
|
return signers.map(({ signer }) => {
|
||||||
|
return (
|
||||||
|
(signer.__typename === 'ETHAddress' && signer.address) ||
|
||||||
|
(signer.__typename === 'PubKey' && signer.key)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="relative" data-testid="proposal-market-data">
|
||||||
|
<button
|
||||||
|
onClick={() => setShowDetails(!showDetails)}
|
||||||
|
data-testid="proposal-market-data-toggle"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<SubHeading title={t('marketSpecification')} />
|
||||||
|
<div className={collapsibleToggleStyles(showDetails)}>
|
||||||
|
<Icon name="chevron-down" size={8} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{showDetails && (
|
||||||
|
<>
|
||||||
|
<div className="float-right">
|
||||||
|
<Button onClick={open} data-testid="view-market-json">
|
||||||
|
{t('viewMarketJson')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="mb-10">
|
||||||
|
<Accordion>
|
||||||
|
<AccordionItem
|
||||||
|
itemId="key-details"
|
||||||
|
title={t('Key details')}
|
||||||
|
content={<KeyDetailsInfoPanel market={marketData} />}
|
||||||
|
/>
|
||||||
|
<AccordionItem
|
||||||
|
itemId="instrument"
|
||||||
|
title={t('Instrument')}
|
||||||
|
content={<InstrumentInfoPanel market={marketData} />}
|
||||||
|
/>
|
||||||
|
{isEqual(
|
||||||
|
getSigners(settlementData),
|
||||||
|
getSigners(terminationData)
|
||||||
|
) ? (
|
||||||
|
<AccordionItem
|
||||||
|
itemId="oracles"
|
||||||
|
title={t('Oracle')}
|
||||||
|
content={
|
||||||
|
<OracleInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
type="settlementData"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<AccordionItem
|
||||||
|
itemId="settlement-oracle"
|
||||||
|
title={t('Settlement Oracle')}
|
||||||
|
content={
|
||||||
|
<OracleInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
type="settlementData"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<AccordionItem
|
||||||
|
itemId="termination-oracle"
|
||||||
|
title={t('Termination Oracle')}
|
||||||
|
content={
|
||||||
|
<OracleInfoPanel market={marketData} type="termination" />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<AccordionItem
|
||||||
|
itemId="settlement-asset"
|
||||||
|
title={t('Settlement asset')}
|
||||||
|
content={<SettlementAssetInfoPanel market={marketData} />}
|
||||||
|
/>
|
||||||
|
<AccordionItem
|
||||||
|
itemId="metadata"
|
||||||
|
title={t('Metadata')}
|
||||||
|
content={<MetadataInfoPanel market={marketData} />}
|
||||||
|
/>
|
||||||
|
<AccordionItem
|
||||||
|
itemId="risk-model"
|
||||||
|
title={t('Risk model')}
|
||||||
|
content={<RiskModelInfoPanel market={marketData} />}
|
||||||
|
/>
|
||||||
|
<AccordionItem
|
||||||
|
itemId="risk-parameters"
|
||||||
|
title={t('Risk parameters')}
|
||||||
|
content={<RiskParametersInfoPanel market={marketData} />}
|
||||||
|
/>
|
||||||
|
<AccordionItem
|
||||||
|
itemId="risk-factors"
|
||||||
|
title={t('Risk factors')}
|
||||||
|
content={<RiskFactorsInfoPanel market={marketData} />}
|
||||||
|
/>
|
||||||
|
{(
|
||||||
|
marketData.priceMonitoringSettings?.parameters?.triggers || []
|
||||||
|
).map((_, triggerIndex) => (
|
||||||
|
<AccordionItem
|
||||||
|
itemId={`trigger-${triggerIndex}`}
|
||||||
|
title={t(`Price monitoring bounds ${triggerIndex + 1}`)}
|
||||||
|
content={
|
||||||
|
<PriceMonitoringBoundsInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
triggerIndex={triggerIndex}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<AccordionItem
|
||||||
|
itemId="liqudity-monitoring-parameters"
|
||||||
|
title={t('Liquidity monitoring parameters')}
|
||||||
|
content={
|
||||||
|
<LiquidityMonitoringParametersInfoPanel market={marketData} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<AccordionItem
|
||||||
|
itemId="liquidity-price-range"
|
||||||
|
title={t('Liquidity price range')}
|
||||||
|
content={<LiquidityPriceRangeInfoPanel market={marketData} />}
|
||||||
|
/>
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
title={marketData.tradableInstrument.instrument.code}
|
||||||
|
open={isOpen}
|
||||||
|
onChange={(isOpen) => (isOpen ? open() : close())}
|
||||||
|
size="medium"
|
||||||
|
dataTestId="market-json-dialog"
|
||||||
|
>
|
||||||
|
<CopyWithTooltip text={JSON.stringify(marketData)}>
|
||||||
|
<button className="bg-vega-dark-100 rounded-sm py-2 px-3 mb-4 text-white">
|
||||||
|
<span>
|
||||||
|
<Icon name="duplicate" />
|
||||||
|
</span>
|
||||||
|
<span className="ml-2">Copy</span>
|
||||||
|
</button>
|
||||||
|
</CopyWithTooltip>
|
||||||
|
<SyntaxHighlighter data={marketData} />
|
||||||
|
</Dialog>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
+2
-6
@@ -1,4 +1,3 @@
|
|||||||
import classnames from 'classnames';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
@@ -13,6 +12,7 @@ import { SubHeading } from '../../../../components/heading';
|
|||||||
import { useVoteInformation } from '../../hooks';
|
import { useVoteInformation } from '../../hooks';
|
||||||
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
||||||
import { ProposalType } from '../proposal/proposal';
|
import { ProposalType } from '../proposal/proposal';
|
||||||
|
import { collapsibleToggleStyles } from '../../../../lib/collapsible-toggle-styles';
|
||||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
@@ -57,10 +57,6 @@ export const ProposalVotesTable = ({
|
|||||||
? t('byTokenVote')
|
? t('byTokenVote')
|
||||||
: t('byLiquidityVote');
|
: t('byLiquidityVote');
|
||||||
|
|
||||||
const showDetailsIconClasses = classnames('mb-4', {
|
|
||||||
'rotate-180': showDetails,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
@@ -69,7 +65,7 @@ export const ProposalVotesTable = ({
|
|||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<SubHeading title={t('voteBreakdown')} />
|
<SubHeading title={t('voteBreakdown')} />
|
||||||
<div className={showDetailsIconClasses}>
|
<div className={collapsibleToggleStyles(showDetails)}>
|
||||||
<Icon name="chevron-down" size={8} />
|
<Icon name="chevron-down" size={8} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { generateProposal } from '../../test-helpers/generate-proposals';
|
import { generateProposal } from '../../test-helpers/generate-proposals';
|
||||||
import { Proposal } from './proposal';
|
import { Proposal } from './proposal';
|
||||||
@@ -28,9 +29,6 @@ jest.mock('../proposal-change-table', () => ({
|
|||||||
jest.mock('../proposal-json', () => ({
|
jest.mock('../proposal-json', () => ({
|
||||||
ProposalJson: () => <div data-testid="proposal-json"></div>,
|
ProposalJson: () => <div data-testid="proposal-json"></div>,
|
||||||
}));
|
}));
|
||||||
jest.mock('../proposal-terms/proposal-terms', () => ({
|
|
||||||
ProposalTerms: () => <div data-testid="proposal-terms"></div>,
|
|
||||||
}));
|
|
||||||
jest.mock('../proposal-votes-table', () => ({
|
jest.mock('../proposal-votes-table', () => ({
|
||||||
ProposalVotesTable: () => <div data-testid="proposal-votes-table"></div>,
|
ProposalVotesTable: () => <div data-testid="proposal-votes-table"></div>,
|
||||||
}));
|
}));
|
||||||
@@ -41,23 +39,38 @@ jest.mock('../list-asset', () => ({
|
|||||||
ListAsset: () => <div data-testid="proposal-list-asset"></div>,
|
ListAsset: () => <div data-testid="proposal-list-asset"></div>,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const renderComponent = (proposal: ProposalQuery['proposal']) => {
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<Proposal
|
||||||
|
restData={{}}
|
||||||
|
proposal={proposal as ProposalQuery['proposal']}
|
||||||
|
/>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
it('Renders with data-testid', async () => {
|
it('Renders with data-testid', async () => {
|
||||||
const proposal = generateProposal();
|
const proposal = generateProposal();
|
||||||
render(
|
renderComponent(proposal);
|
||||||
<Proposal restData={{}} proposal={proposal as ProposalQuery['proposal']} />
|
|
||||||
);
|
|
||||||
expect(await screen.findByTestId('proposal')).toBeInTheDocument();
|
expect(await screen.findByTestId('proposal')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Renders with a link back to "all proposals"', async () => {
|
||||||
|
const proposal = generateProposal();
|
||||||
|
renderComponent(proposal);
|
||||||
|
|
||||||
|
expect(await screen.findByTestId('all-proposals-link')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('renders each section', async () => {
|
it('renders each section', async () => {
|
||||||
const proposal = generateProposal();
|
const proposal = generateProposal();
|
||||||
render(
|
renderComponent(proposal);
|
||||||
<Proposal restData={{}} proposal={proposal as ProposalQuery['proposal']} />
|
|
||||||
);
|
|
||||||
expect(await screen.findByTestId('proposal-header')).toBeInTheDocument();
|
expect(await screen.findByTestId('proposal-header')).toBeInTheDocument();
|
||||||
expect(screen.getByTestId('proposal-change-table')).toBeInTheDocument();
|
expect(screen.getByTestId('proposal-change-table')).toBeInTheDocument();
|
||||||
expect(screen.getByTestId('proposal-json')).toBeInTheDocument();
|
expect(screen.getByTestId('proposal-json')).toBeInTheDocument();
|
||||||
expect(screen.getByTestId('proposal-terms')).toBeInTheDocument();
|
|
||||||
expect(screen.getByTestId('proposal-votes-table')).toBeInTheDocument();
|
expect(screen.getByTestId('proposal-votes-table')).toBeInTheDocument();
|
||||||
expect(screen.getByTestId('proposal-vote-details')).toBeInTheDocument();
|
expect(screen.getByTestId('proposal-vote-details')).toBeInTheDocument();
|
||||||
expect(screen.queryByTestId('proposal-list-asset')).not.toBeInTheDocument();
|
expect(screen.queryByTestId('proposal-list-asset')).not.toBeInTheDocument();
|
||||||
@@ -80,8 +93,7 @@ it('renders whitelist section if proposal is new asset and source is erc20', asy
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
render(
|
renderComponent(proposal);
|
||||||
<Proposal restData={{}} proposal={proposal as ProposalQuery['proposal']} />
|
|
||||||
);
|
|
||||||
expect(screen.getByTestId('proposal-list-asset')).toBeInTheDocument();
|
expect(screen.getByTestId('proposal-list-asset')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
NetworkParams,
|
NetworkParams,
|
||||||
useNetworkParams,
|
useNetworkParams,
|
||||||
} from '@vegaprotocol/network-parameters';
|
} from '@vegaprotocol/network-parameters';
|
||||||
import { AsyncRenderer, RoundedWrapper } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, Icon, RoundedWrapper } from '@vegaprotocol/ui-toolkit';
|
||||||
import { ProposalHeader } from '../proposal-detail-header/proposal-header';
|
import { ProposalHeader } from '../proposal-detail-header/proposal-header';
|
||||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
|
||||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
|
||||||
import { ProposalDescription } from '../proposal-description';
|
import { ProposalDescription } from '../proposal-description';
|
||||||
import { ProposalChangeTable } from '../proposal-change-table';
|
import { ProposalChangeTable } from '../proposal-change-table';
|
||||||
import { ProposalJson } from '../proposal-json';
|
import { ProposalJson } from '../proposal-json';
|
||||||
import { ProposalTerms } from '../proposal-terms';
|
|
||||||
import { ProposalVotesTable } from '../proposal-votes-table';
|
import { ProposalVotesTable } from '../proposal-votes-table';
|
||||||
import { VoteDetails } from '../vote-details';
|
import { VoteDetails } from '../vote-details';
|
||||||
import { ListAsset } from '../list-asset';
|
import { ListAsset } from '../list-asset';
|
||||||
|
import Routes from '../../../routes';
|
||||||
|
import { ProposalMarketData } from '../proposal-market-data';
|
||||||
|
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||||
|
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||||
|
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||||
|
|
||||||
export enum ProposalType {
|
export enum ProposalType {
|
||||||
PROPOSAL_NEW_MARKET = 'PROPOSAL_NEW_MARKET',
|
PROPOSAL_NEW_MARKET = 'PROPOSAL_NEW_MARKET',
|
||||||
@@ -24,11 +28,17 @@ export enum ProposalType {
|
|||||||
}
|
}
|
||||||
export interface ProposalProps {
|
export interface ProposalProps {
|
||||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||||
|
newMarketData?: MarketInfoWithData | null;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
restData: any;
|
restData: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Proposal = ({ proposal, restData }: ProposalProps) => {
|
export const Proposal = ({
|
||||||
|
proposal,
|
||||||
|
restData,
|
||||||
|
newMarketData,
|
||||||
|
}: ProposalProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { params, loading, error } = useNetworkParams([
|
const { params, loading, error } = useNetworkParams([
|
||||||
NetworkParams.governance_proposal_market_minVoterBalance,
|
NetworkParams.governance_proposal_market_minVoterBalance,
|
||||||
NetworkParams.governance_proposal_updateMarket_minVoterBalance,
|
NetworkParams.governance_proposal_updateMarket_minVoterBalance,
|
||||||
@@ -81,52 +91,69 @@ export const Proposal = ({ proposal, restData }: ProposalProps) => {
|
|||||||
return (
|
return (
|
||||||
<AsyncRenderer data={params} loading={loading} error={error}>
|
<AsyncRenderer data={params} loading={loading} error={error}>
|
||||||
<section data-testid="proposal">
|
<section data-testid="proposal">
|
||||||
|
<div
|
||||||
|
className="flex items-center gap-1"
|
||||||
|
data-testid="all-proposals-link"
|
||||||
|
>
|
||||||
|
<Icon name={'chevron-left'} />
|
||||||
|
<Link className="underline" to={Routes.PROPOSALS}>
|
||||||
|
{t('AllProposals')}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
<ProposalHeader proposal={proposal} isListItem={false} />
|
<ProposalHeader proposal={proposal} isListItem={false} />
|
||||||
|
|
||||||
<div className="my-10">
|
<div id="details">
|
||||||
<ProposalChangeTable proposal={proposal} />
|
<div className="my-10">
|
||||||
</div>
|
<ProposalChangeTable proposal={proposal} />
|
||||||
|
</div>
|
||||||
|
|
||||||
{proposal.terms.change.__typename === 'NewAsset' &&
|
{proposal.terms.change.__typename === 'NewAsset' &&
|
||||||
proposal.terms.change.source.__typename === 'ERC20' &&
|
proposal.terms.change.source.__typename === 'ERC20' &&
|
||||||
proposal.id ? (
|
proposal.id ? (
|
||||||
<ListAsset
|
<ListAsset
|
||||||
assetId={proposal.id}
|
assetId={proposal.id}
|
||||||
withdrawalThreshold={proposal.terms.change.source.withdrawThreshold}
|
withdrawalThreshold={
|
||||||
lifetimeLimit={proposal.terms.change.source.lifetimeLimit}
|
proposal.terms.change.source.withdrawThreshold
|
||||||
/>
|
}
|
||||||
) : null}
|
lifetimeLimit={proposal.terms.change.source.lifetimeLimit}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<ProposalDescription description={proposal.rationale.description} />
|
<ProposalDescription description={proposal.rationale.description} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{proposal.terms.change.__typename !== 'NewMarket' &&
|
{newMarketData && (
|
||||||
proposal.terms.change.__typename !== 'UpdateMarket' && (
|
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<ProposalTerms data={proposal.terms} />
|
<ProposalMarketData marketData={newMarketData} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<ProposalJson proposal={restData?.data?.proposal} />
|
<ProposalJson proposal={restData?.data?.proposal} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-10">
|
<div id="voting">
|
||||||
<RoundedWrapper paddingBottom={true}>
|
<div className="mb-10">
|
||||||
<VoteDetails
|
<RoundedWrapper paddingBottom={true}>
|
||||||
|
<VoteDetails
|
||||||
|
proposal={proposal}
|
||||||
|
proposalType={proposalType}
|
||||||
|
minVoterBalance={minVoterBalance}
|
||||||
|
spamProtectionMinTokens={
|
||||||
|
params?.spam_protection_voting_min_tokens
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</RoundedWrapper>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4">
|
||||||
|
<ProposalVotesTable
|
||||||
proposal={proposal}
|
proposal={proposal}
|
||||||
proposalType={proposalType}
|
proposalType={proposalType}
|
||||||
minVoterBalance={minVoterBalance}
|
|
||||||
spamProtectionMinTokens={
|
|
||||||
params?.spam_protection_voting_min_tokens
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</RoundedWrapper>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-4">
|
|
||||||
<ProposalVotesTable proposal={proposal} proposalType={proposalType} />
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</AsyncRenderer>
|
</AsyncRenderer>
|
||||||
|
|||||||
+42
-2
@@ -146,7 +146,7 @@ describe('Proposal form vote, validation and enactment deadline', () => {
|
|||||||
it('should show the correct datetimes', () => {
|
it('should show the correct datetimes', () => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
// Should be adding 2 mins to the vote deadline as the minimum is set by
|
// Should be adding 2 mins to the vote deadline as the minimum is set by
|
||||||
// default, and we add 2 mins for wallet confirmation
|
// default, and 2 mins are added for wallet confirmation
|
||||||
expect(screen.getByTestId('voting-date')).toHaveTextContent(
|
expect(screen.getByTestId('voting-date')).toHaveTextContent(
|
||||||
'2022-01-01T01:02:00.000Z'
|
'2022-01-01T01:02:00.000Z'
|
||||||
);
|
);
|
||||||
@@ -224,7 +224,47 @@ describe('Proposal form vote, validation and enactment deadline', () => {
|
|||||||
expect(
|
expect(
|
||||||
screen.getByTestId('enactment-before-voting-deadline')
|
screen.getByTestId('enactment-before-voting-deadline')
|
||||||
).toHaveTextContent(
|
).toHaveTextContent(
|
||||||
'Proposal will fail if enactment is earlier than the voting deadline'
|
'The proposal will fail if enactment is earlier than the voting deadline'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays error text if the vote deadline is set earlier than the minimum allowed', () => {
|
||||||
|
renderComponent();
|
||||||
|
const voteDeadlineInput = screen.getByTestId('proposal-vote-deadline');
|
||||||
|
fireEvent.change(voteDeadlineInput, { target: { value: 0.01 } });
|
||||||
|
expect(screen.getByTestId('voting-less-than-min')).toHaveTextContent(
|
||||||
|
'The proposal will fail if voting deadline is below the minimum'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays error text if the vote deadline is set later than the maximum allowed', () => {
|
||||||
|
renderComponent();
|
||||||
|
const voteDeadlineInput = screen.getByTestId('proposal-vote-deadline');
|
||||||
|
fireEvent.change(voteDeadlineInput, { target: { value: 100000 } });
|
||||||
|
expect(screen.getByTestId('voting-greater-than-max')).toHaveTextContent(
|
||||||
|
'The proposal will fail if voting deadline is above the maximum'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays error text if the enactment deadline is set earlier than the minimum allowed', () => {
|
||||||
|
renderComponent();
|
||||||
|
const enactmentDeadlineInput = screen.getByTestId(
|
||||||
|
'proposal-enactment-deadline'
|
||||||
|
);
|
||||||
|
fireEvent.change(enactmentDeadlineInput, { target: { value: 0.01 } });
|
||||||
|
expect(screen.getByTestId('enactment-less-than-min')).toHaveTextContent(
|
||||||
|
'The proposal will fail if enactment deadline is below the minimum'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays error text if the enactment deadline is set later than the maximum allowed', () => {
|
||||||
|
renderComponent();
|
||||||
|
const enactmentDeadlineInput = screen.getByTestId(
|
||||||
|
'proposal-enactment-deadline'
|
||||||
|
);
|
||||||
|
fireEvent.change(enactmentDeadlineInput, { target: { value: 100000 } });
|
||||||
|
expect(screen.getByTestId('enactment-greater-than-max')).toHaveTextContent(
|
||||||
|
'The proposal will fail if enactment deadline is above the maximum'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+62
-22
@@ -220,21 +220,41 @@ const EnactmentForm = ({
|
|||||||
<span data-testid="enactment-date" className="pl-2">
|
<span data-testid="enactment-date" className="pl-2">
|
||||||
{getDateTimeFormat().format(deadlineDates.enactment)}
|
{getDateTimeFormat().format(deadlineDates.enactment)}
|
||||||
</span>
|
</span>
|
||||||
{deadlines.enactment === minEnactmentHours && (
|
{deadlines.enactment && (
|
||||||
<span
|
<>
|
||||||
data-testid="enactment-2-mins-extra"
|
{deadlines.enactment === minEnactmentHours && (
|
||||||
className="block mt-4 font-light"
|
<span
|
||||||
>
|
data-testid="enactment-2-mins-extra"
|
||||||
{t('ThisWillAdd2MinutesToAllowTimeToConfirmInWallet')}
|
className="block mt-4 font-light"
|
||||||
</span>
|
>
|
||||||
)}
|
{t('ThisWillAdd2MinutesToAllowTimeToConfirmInWallet')}
|
||||||
{deadlines.enactment && deadlines.enactment < deadlines.vote && (
|
</span>
|
||||||
<span
|
)}
|
||||||
data-testid="enactment-before-voting-deadline"
|
{deadlines.enactment < deadlines.vote && (
|
||||||
className="block mt-4 text-vega-pink"
|
<span
|
||||||
>
|
data-testid="enactment-before-voting-deadline"
|
||||||
{t('ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline')}
|
className="block mt-4 text-vega-pink"
|
||||||
</span>
|
>
|
||||||
|
{t('ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{deadlines.enactment < minEnactmentHours && (
|
||||||
|
<span
|
||||||
|
data-testid="enactment-less-than-min"
|
||||||
|
className="block mt-4 text-vega-pink"
|
||||||
|
>
|
||||||
|
{t('ProposalWillFailIfEnactmentIsBelowTheMinimumDeadline')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{deadlines.enactment > maxEnactmentHours && (
|
||||||
|
<span
|
||||||
|
data-testid="enactment-greater-than-max"
|
||||||
|
className="block mt-4 text-vega-pink"
|
||||||
|
>
|
||||||
|
{t('ProposalWillFailIfEnactmentIsAboveTheMaximumDeadline')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -500,13 +520,33 @@ export function ProposalFormVoteAndEnactmentDeadline({
|
|||||||
<span data-testid="voting-date" className="pl-2">
|
<span data-testid="voting-date" className="pl-2">
|
||||||
{getDateTimeFormat().format(deadlineDates.vote)}
|
{getDateTimeFormat().format(deadlineDates.vote)}
|
||||||
</span>
|
</span>
|
||||||
{deadlines.vote === minVoteHours && (
|
{deadlines.vote && (
|
||||||
<span
|
<>
|
||||||
data-testid="voting-2-mins-extra"
|
{deadlines.vote === minVoteHours && (
|
||||||
className="block mt-4 font-light"
|
<span
|
||||||
>
|
data-testid="voting-2-mins-extra"
|
||||||
{t('ThisWillAdd2MinutesToAllowTimeToConfirmInWallet')}
|
className="block mt-4 font-light"
|
||||||
</span>
|
>
|
||||||
|
{t('ThisWillAdd2MinutesToAllowTimeToConfirmInWallet')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{deadlines.vote < minVoteHours && (
|
||||||
|
<span
|
||||||
|
data-testid="voting-less-than-min"
|
||||||
|
className="block mt-4 text-vega-pink"
|
||||||
|
>
|
||||||
|
{t('ProposalWillFailIfVotingIsBelowTheMinimumDeadline')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{deadlines.vote > maxVoteHours && (
|
||||||
|
<span
|
||||||
|
data-testid="voting-greater-than-max"
|
||||||
|
className="block mt-4 text-vega-pink"
|
||||||
|
>
|
||||||
|
{t('ProposalWillFailIfVotingIsAboveTheMaximumDeadline')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { captureMessage } from '@sentry/minimal';
|
import { captureMessage } from '@sentry/minimal';
|
||||||
|
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { VoteValue } from '@vegaprotocol/types';
|
import { VoteValue } from '@vegaprotocol/types';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useUserVoteQuery } from './__generated__/Vote';
|
import { useUserVoteQuery } from './__generated__/Vote';
|
||||||
import type { FinalizedVote } from '@vegaprotocol/proposals';
|
|
||||||
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||||
|
import type { FinalizedVote } from '@vegaprotocol/proposals';
|
||||||
|
|
||||||
export enum VoteState {
|
export enum VoteState {
|
||||||
NotCast = 'NotCast',
|
NotCast = 'NotCast',
|
||||||
@@ -45,21 +44,23 @@ export function useUserVote(
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (finalizedVote?.vote.value) {
|
if (finalizedVote?.vote.value && finalizedVote.pubKey === pubKey) {
|
||||||
setUserVote(finalizedVote);
|
setUserVote(finalizedVote);
|
||||||
} else if (data?.party?.votesConnection?.edges) {
|
} else if (data?.party?.votesConnection?.edges && pubKey) {
|
||||||
// This sets the vote (if any) when the user first loads the page
|
const vote = removePaginationWrapper(
|
||||||
setUserVote(
|
data?.party?.votesConnection?.edges
|
||||||
removePaginationWrapper(data?.party?.votesConnection?.edges).find(
|
).find(({ proposalId: pId }) => proposalId === pId);
|
||||||
({ proposalId: pId }) => proposalId === pId
|
|
||||||
)
|
if (vote) {
|
||||||
);
|
setUserVote({ ...vote, pubKey });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
finalizedVote?.vote.value,
|
finalizedVote?.vote.value,
|
||||||
data?.party?.votesConnection?.edges,
|
data?.party?.votesConnection?.edges,
|
||||||
finalizedVote,
|
finalizedVote,
|
||||||
proposalId,
|
proposalId,
|
||||||
|
pubKey,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// If user vote changes update the vote state
|
// If user vote changes update the vote state
|
||||||
@@ -94,6 +95,8 @@ export function useUserVote(
|
|||||||
return {
|
return {
|
||||||
voteState,
|
voteState,
|
||||||
userVote,
|
userVote,
|
||||||
voteDatetime: userVote ? new Date(userVote.vote.datetime) : null,
|
voteDatetime: userVote?.vote?.datetime
|
||||||
|
? new Date(userVote.vote.datetime)
|
||||||
|
: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { ProposalNotFound } from '../components/proposal-not-found';
|
|||||||
import { useProposalQuery } from './__generated__/Proposal';
|
import { useProposalQuery } from './__generated__/Proposal';
|
||||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||||
import { ENV } from '../../../config';
|
import { ENV } from '../../../config';
|
||||||
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
|
import { marketInfoWithDataProvider } from '@vegaprotocol/markets';
|
||||||
|
|
||||||
export const ProposalContainer = () => {
|
export const ProposalContainer = () => {
|
||||||
const params = useParams<{ proposalId: string }>();
|
const params = useParams<{ proposalId: string }>();
|
||||||
@@ -20,15 +22,36 @@ export const ProposalContainer = () => {
|
|||||||
skip: !params.proposalId,
|
skip: !params.proposalId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: newMarketData,
|
||||||
|
loading: newMarketLoading,
|
||||||
|
error: newMarketError,
|
||||||
|
} = useDataProvider({
|
||||||
|
dataProvider: marketInfoWithDataProvider,
|
||||||
|
skipUpdates: true,
|
||||||
|
variables: {
|
||||||
|
marketId: data?.proposal?.id || '',
|
||||||
|
skip: !data?.proposal?.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(refetch, 1000);
|
const interval = setInterval(refetch, 2000);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [refetch]);
|
}, [refetch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
<AsyncRenderer
|
||||||
|
loading={loading || newMarketLoading}
|
||||||
|
error={error || newMarketError}
|
||||||
|
data={newMarketData ? { newMarketData, data } : data}
|
||||||
|
>
|
||||||
{data?.proposal ? (
|
{data?.proposal ? (
|
||||||
<Proposal proposal={data.proposal} restData={restData} />
|
<Proposal
|
||||||
|
proposal={data.proposal}
|
||||||
|
restData={restData}
|
||||||
|
newMarketData={newMarketData}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ProposalNotFound />
|
<ProposalNotFound />
|
||||||
)}
|
)}
|
||||||
|
|||||||
+1
@@ -8,6 +8,7 @@ const mockData = {
|
|||||||
{
|
{
|
||||||
asset: 'tDAI',
|
asset: 'tDAI',
|
||||||
totalAmount: '5',
|
totalAmount: '5',
|
||||||
|
decimals: 6,
|
||||||
rewardTypes: {
|
rewardTypes: {
|
||||||
ACCOUNT_TYPE_GLOBAL_REWARD: {
|
ACCOUNT_TYPE_GLOBAL_REWARD: {
|
||||||
amount: '0',
|
amount: '0',
|
||||||
|
|||||||
+20
-10
@@ -1,6 +1,5 @@
|
|||||||
import { formatNumber, toBigNum } from '@vegaprotocol/utils';
|
import { formatNumber, toBigNum } from '@vegaprotocol/utils';
|
||||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useAppState } from '../../../contexts/app-state/app-state-context';
|
|
||||||
import {
|
import {
|
||||||
rowGridItemStyles,
|
rowGridItemStyles,
|
||||||
RewardsTable,
|
RewardsTable,
|
||||||
@@ -13,7 +12,8 @@ interface EpochIndividualRewardsGridProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface RewardItemProps {
|
interface RewardItemProps {
|
||||||
value: string;
|
amount: string;
|
||||||
|
decimals: number;
|
||||||
percentageOfTotal?: string;
|
percentageOfTotal?: string;
|
||||||
dataTestId: string;
|
dataTestId: string;
|
||||||
last?: boolean;
|
last?: boolean;
|
||||||
@@ -21,15 +21,14 @@ interface RewardItemProps {
|
|||||||
|
|
||||||
const DisplayReward = ({
|
const DisplayReward = ({
|
||||||
reward,
|
reward,
|
||||||
|
decimals,
|
||||||
percentageOfTotal,
|
percentageOfTotal,
|
||||||
}: {
|
}: {
|
||||||
reward: string;
|
reward: string;
|
||||||
|
decimals: number;
|
||||||
percentageOfTotal?: string;
|
percentageOfTotal?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
|
||||||
appState: { decimals },
|
|
||||||
} = useAppState();
|
|
||||||
|
|
||||||
if (Number(reward) === 0) {
|
if (Number(reward) === 0) {
|
||||||
return <span className="text-vega-dark-300">-</span>;
|
return <span className="text-vega-dark-300">-</span>;
|
||||||
@@ -64,7 +63,8 @@ const DisplayReward = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const RewardItem = ({
|
const RewardItem = ({
|
||||||
value,
|
amount,
|
||||||
|
decimals,
|
||||||
percentageOfTotal,
|
percentageOfTotal,
|
||||||
dataTestId,
|
dataTestId,
|
||||||
last,
|
last,
|
||||||
@@ -72,7 +72,11 @@ const RewardItem = ({
|
|||||||
<div data-testid={dataTestId} className={rowGridItemStyles(last)}>
|
<div data-testid={dataTestId} className={rowGridItemStyles(last)}>
|
||||||
<div className="h-full w-5 absolute right-0 top-0 bg-gradient-to-r from-transparent to-black pointer-events-none" />
|
<div className="h-full w-5 absolute right-0 top-0 bg-gradient-to-r from-transparent to-black pointer-events-none" />
|
||||||
<div className="overflow-auto p-5">
|
<div className="overflow-auto p-5">
|
||||||
<DisplayReward reward={value} percentageOfTotal={percentageOfTotal} />
|
<DisplayReward
|
||||||
|
reward={amount}
|
||||||
|
decimals={decimals}
|
||||||
|
percentageOfTotal={percentageOfTotal}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full w-5 absolute left-0 top-0 bg-gradient-to-l from-transparent to-black pointer-events-none" />
|
<div className="h-full w-5 absolute left-0 top-0 bg-gradient-to-l from-transparent to-black pointer-events-none" />
|
||||||
</div>
|
</div>
|
||||||
@@ -86,7 +90,7 @@ export const EpochIndividualRewardsTable = ({
|
|||||||
dataTestId="epoch-individual-rewards-table"
|
dataTestId="epoch-individual-rewards-table"
|
||||||
epoch={Number(data.epoch)}
|
epoch={Number(data.epoch)}
|
||||||
>
|
>
|
||||||
{data.rewards.map(({ asset, rewardTypes, totalAmount }, i) => (
|
{data.rewards.map(({ asset, rewardTypes, totalAmount, decimals }, i) => (
|
||||||
<div className="contents" key={i}>
|
<div className="contents" key={i}>
|
||||||
<div
|
<div
|
||||||
data-testid="individual-rewards-asset"
|
data-testid="individual-rewards-asset"
|
||||||
@@ -98,13 +102,19 @@ export const EpochIndividualRewardsTable = ({
|
|||||||
([key, { amount, percentageOfTotal }]) => (
|
([key, { amount, percentageOfTotal }]) => (
|
||||||
<RewardItem
|
<RewardItem
|
||||||
key={key}
|
key={key}
|
||||||
value={amount}
|
amount={amount}
|
||||||
|
decimals={decimals}
|
||||||
percentageOfTotal={percentageOfTotal}
|
percentageOfTotal={percentageOfTotal}
|
||||||
dataTestId={key}
|
dataTestId={key}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
<RewardItem dataTestId="total" value={totalAmount} last={true} />
|
<RewardItem
|
||||||
|
dataTestId="total"
|
||||||
|
amount={totalAmount}
|
||||||
|
decimals={decimals}
|
||||||
|
last={true}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</RewardsTable>
|
</RewardsTable>
|
||||||
|
|||||||
+8
-1
@@ -48,15 +48,22 @@ export const EpochIndividualRewards = ({
|
|||||||
return removePaginationWrapper(data.party.rewardsConnection.edges);
|
return removePaginationWrapper(data.party.rewardsConnection.edges);
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
|
const epochRewardSummaries = useMemo(() => {
|
||||||
|
if (!data?.epochRewardSummaries) return [];
|
||||||
|
|
||||||
|
return removePaginationWrapper(data.epochRewardSummaries.edges);
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
const epochIndividualRewardSummaries = useMemo(() => {
|
const epochIndividualRewardSummaries = useMemo(() => {
|
||||||
if (!data?.party) return [];
|
if (!data?.party) return [];
|
||||||
return generateEpochIndividualRewardsList({
|
return generateEpochIndividualRewardsList({
|
||||||
rewards,
|
rewards,
|
||||||
epochId,
|
epochId,
|
||||||
|
epochRewardSummaries,
|
||||||
page,
|
page,
|
||||||
size: EPOCHS_PAGE_SIZE,
|
size: EPOCHS_PAGE_SIZE,
|
||||||
});
|
});
|
||||||
}, [data?.party, epochId, page, rewards]);
|
}, [data?.party, epochId, epochRewardSummaries, page, rewards]);
|
||||||
|
|
||||||
const refetchData = useCallback(
|
const refetchData = useCallback(
|
||||||
async (toPage?: number) => {
|
async (toPage?: number) => {
|
||||||
|
|||||||
+112
-10
@@ -8,7 +8,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
amount: '100',
|
amount: '100',
|
||||||
percentageOfTotal: '0.1',
|
percentageOfTotal: '0.1',
|
||||||
receivedAt: new Date(),
|
receivedAt: new Date(),
|
||||||
asset: { id: 'usd', symbol: 'USD', name: 'USD' },
|
asset: { id: 'usd', symbol: 'USD', name: 'USD', decimals: 6 },
|
||||||
party: { id: 'blah' },
|
party: { id: 'blah' },
|
||||||
epoch: { id: '1' },
|
epoch: { id: '1' },
|
||||||
};
|
};
|
||||||
@@ -18,7 +18,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
amount: '50',
|
amount: '50',
|
||||||
percentageOfTotal: '0.05',
|
percentageOfTotal: '0.05',
|
||||||
receivedAt: new Date(),
|
receivedAt: new Date(),
|
||||||
asset: { id: 'eur', symbol: 'EUR', name: 'EUR' },
|
asset: { id: 'eur', symbol: 'EUR', name: 'EUR', decimals: 5 },
|
||||||
party: { id: 'blah' },
|
party: { id: 'blah' },
|
||||||
epoch: { id: '2' },
|
epoch: { id: '2' },
|
||||||
};
|
};
|
||||||
@@ -28,7 +28,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
amount: '200',
|
amount: '200',
|
||||||
percentageOfTotal: '0.2',
|
percentageOfTotal: '0.2',
|
||||||
receivedAt: new Date(),
|
receivedAt: new Date(),
|
||||||
asset: { id: 'gbp', symbol: 'GBP', name: 'GBP' },
|
asset: { id: 'gbp', symbol: 'GBP', name: 'GBP', decimals: 7 },
|
||||||
party: { id: 'blah' },
|
party: { id: 'blah' },
|
||||||
epoch: { id: '2' },
|
epoch: { id: '2' },
|
||||||
};
|
};
|
||||||
@@ -38,7 +38,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
amount: '100',
|
amount: '100',
|
||||||
percentageOfTotal: '0.1',
|
percentageOfTotal: '0.1',
|
||||||
receivedAt: new Date(),
|
receivedAt: new Date(),
|
||||||
asset: { id: 'usd', symbol: 'USD', name: 'USD' },
|
asset: { id: 'usd', symbol: 'USD', name: 'USD', decimals: 6 },
|
||||||
party: { id: 'blah' },
|
party: { id: 'blah' },
|
||||||
epoch: { id: '1' },
|
epoch: { id: '1' },
|
||||||
};
|
};
|
||||||
@@ -48,7 +48,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
amount: '150',
|
amount: '150',
|
||||||
percentageOfTotal: '0.15',
|
percentageOfTotal: '0.15',
|
||||||
receivedAt: new Date(),
|
receivedAt: new Date(),
|
||||||
asset: { id: 'usd', symbol: 'USD', name: 'USD' },
|
asset: { id: 'usd', symbol: 'USD', name: 'USD', decimals: 6 },
|
||||||
party: { id: 'blah' },
|
party: { id: 'blah' },
|
||||||
epoch: { id: '3' },
|
epoch: { id: '3' },
|
||||||
};
|
};
|
||||||
@@ -58,14 +58,18 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
amount: '50',
|
amount: '50',
|
||||||
percentageOfTotal: '0.05',
|
percentageOfTotal: '0.05',
|
||||||
receivedAt: new Date(),
|
receivedAt: new Date(),
|
||||||
asset: { id: 'eur', symbol: 'EUR', name: 'EUR' },
|
asset: { id: 'eur', symbol: 'EUR', name: 'EUR', decimals: 5 },
|
||||||
party: { id: 'blah' },
|
party: { id: 'blah' },
|
||||||
epoch: { id: '2' },
|
epoch: { id: '2' },
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should return an empty array if no rewards are provided', () => {
|
it('should return an empty array if no rewards are provided', () => {
|
||||||
expect(
|
expect(
|
||||||
generateEpochIndividualRewardsList({ rewards: [], epochId: 1 })
|
generateEpochIndividualRewardsList({
|
||||||
|
rewards: [],
|
||||||
|
epochId: 1,
|
||||||
|
epochRewardSummaries: [],
|
||||||
|
})
|
||||||
).toEqual([
|
).toEqual([
|
||||||
{
|
{
|
||||||
epoch: 1,
|
epoch: 1,
|
||||||
@@ -78,6 +82,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
const result = generateEpochIndividualRewardsList({
|
const result = generateEpochIndividualRewardsList({
|
||||||
rewards: [rewardWrongType],
|
rewards: [rewardWrongType],
|
||||||
epochId: 1,
|
epochId: 1,
|
||||||
|
epochRewardSummaries: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
@@ -92,6 +97,15 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
const result = generateEpochIndividualRewardsList({
|
const result = generateEpochIndividualRewardsList({
|
||||||
rewards: [reward1],
|
rewards: [reward1],
|
||||||
epochId: 1,
|
epochId: 1,
|
||||||
|
epochRewardSummaries: [
|
||||||
|
{
|
||||||
|
__typename: 'EpochRewardSummary',
|
||||||
|
epoch: 1,
|
||||||
|
assetId: 'usd',
|
||||||
|
amount: '100000',
|
||||||
|
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result[0]).toEqual({
|
expect(result[0]).toEqual({
|
||||||
@@ -99,6 +113,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
rewards: [
|
rewards: [
|
||||||
{
|
{
|
||||||
asset: 'USD',
|
asset: 'USD',
|
||||||
|
decimals: 6,
|
||||||
totalAmount: '100',
|
totalAmount: '100',
|
||||||
rewardTypes: {
|
rewardTypes: {
|
||||||
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||||
@@ -133,7 +148,11 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
|
|
||||||
it('should return an array sorted by epoch descending', () => {
|
it('should return an array sorted by epoch descending', () => {
|
||||||
const rewards = [reward1, reward2, reward3, reward4];
|
const rewards = [reward1, reward2, reward3, reward4];
|
||||||
const result1 = generateEpochIndividualRewardsList({ rewards, epochId: 2 });
|
const result1 = generateEpochIndividualRewardsList({
|
||||||
|
rewards,
|
||||||
|
epochId: 2,
|
||||||
|
epochRewardSummaries: [],
|
||||||
|
});
|
||||||
|
|
||||||
expect(result1[0].epoch).toEqual(2);
|
expect(result1[0].epoch).toEqual(2);
|
||||||
expect(result1[1].epoch).toEqual(1);
|
expect(result1[1].epoch).toEqual(1);
|
||||||
@@ -142,6 +161,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
const result2 = generateEpochIndividualRewardsList({
|
const result2 = generateEpochIndividualRewardsList({
|
||||||
rewards: reorderedRewards,
|
rewards: reorderedRewards,
|
||||||
epochId: 2,
|
epochId: 2,
|
||||||
|
epochRewardSummaries: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result2[0].epoch).toEqual(2);
|
expect(result2[0].epoch).toEqual(2);
|
||||||
@@ -150,7 +170,11 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
|
|
||||||
it('correctly calculates the total value of rewards for an asset', () => {
|
it('correctly calculates the total value of rewards for an asset', () => {
|
||||||
const rewards = [reward1, reward4];
|
const rewards = [reward1, reward4];
|
||||||
const result = generateEpochIndividualRewardsList({ rewards, epochId: 1 });
|
const result = generateEpochIndividualRewardsList({
|
||||||
|
rewards,
|
||||||
|
epochId: 1,
|
||||||
|
epochRewardSummaries: [],
|
||||||
|
});
|
||||||
|
|
||||||
expect(result[0].rewards[0].totalAmount).toEqual('200');
|
expect(result[0].rewards[0].totalAmount).toEqual('200');
|
||||||
});
|
});
|
||||||
@@ -158,7 +182,11 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
it('returns data in the expected shape', () => {
|
it('returns data in the expected shape', () => {
|
||||||
// Just sanity checking the whole structure here
|
// Just sanity checking the whole structure here
|
||||||
const rewards = [reward1, reward2, reward3, reward4];
|
const rewards = [reward1, reward2, reward3, reward4];
|
||||||
const result = generateEpochIndividualRewardsList({ rewards, epochId: 2 });
|
const result = generateEpochIndividualRewardsList({
|
||||||
|
rewards,
|
||||||
|
epochId: 2,
|
||||||
|
epochRewardSummaries: [],
|
||||||
|
});
|
||||||
|
|
||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
{
|
{
|
||||||
@@ -167,6 +195,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
{
|
{
|
||||||
asset: 'GBP',
|
asset: 'GBP',
|
||||||
totalAmount: '200',
|
totalAmount: '200',
|
||||||
|
decimals: 7,
|
||||||
rewardTypes: {
|
rewardTypes: {
|
||||||
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||||
amount: '0',
|
amount: '0',
|
||||||
@@ -197,6 +226,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
{
|
{
|
||||||
asset: 'EUR',
|
asset: 'EUR',
|
||||||
totalAmount: '50',
|
totalAmount: '50',
|
||||||
|
decimals: 5,
|
||||||
rewardTypes: {
|
rewardTypes: {
|
||||||
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||||
amount: '0',
|
amount: '0',
|
||||||
@@ -232,6 +262,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
{
|
{
|
||||||
asset: 'USD',
|
asset: 'USD',
|
||||||
totalAmount: '200',
|
totalAmount: '200',
|
||||||
|
decimals: 6,
|
||||||
rewardTypes: {
|
rewardTypes: {
|
||||||
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||||
amount: '0',
|
amount: '0',
|
||||||
@@ -269,6 +300,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
const resultPageOne = generateEpochIndividualRewardsList({
|
const resultPageOne = generateEpochIndividualRewardsList({
|
||||||
rewards,
|
rewards,
|
||||||
epochId: 3,
|
epochId: 3,
|
||||||
|
epochRewardSummaries: [],
|
||||||
page: 1,
|
page: 1,
|
||||||
size: 2,
|
size: 2,
|
||||||
});
|
});
|
||||||
@@ -279,6 +311,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
rewards: [
|
rewards: [
|
||||||
{
|
{
|
||||||
asset: 'USD',
|
asset: 'USD',
|
||||||
|
decimals: 6,
|
||||||
totalAmount: '150',
|
totalAmount: '150',
|
||||||
rewardTypes: {
|
rewardTypes: {
|
||||||
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||||
@@ -315,6 +348,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
{
|
{
|
||||||
asset: 'GBP',
|
asset: 'GBP',
|
||||||
totalAmount: '200',
|
totalAmount: '200',
|
||||||
|
decimals: 7,
|
||||||
rewardTypes: {
|
rewardTypes: {
|
||||||
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||||
amount: '0',
|
amount: '0',
|
||||||
@@ -345,6 +379,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
{
|
{
|
||||||
asset: 'EUR',
|
asset: 'EUR',
|
||||||
totalAmount: '50',
|
totalAmount: '50',
|
||||||
|
decimals: 5,
|
||||||
rewardTypes: {
|
rewardTypes: {
|
||||||
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||||
amount: '0',
|
amount: '0',
|
||||||
@@ -379,6 +414,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
const resultPageTwo = generateEpochIndividualRewardsList({
|
const resultPageTwo = generateEpochIndividualRewardsList({
|
||||||
rewards,
|
rewards,
|
||||||
epochId: 3,
|
epochId: 3,
|
||||||
|
epochRewardSummaries: [],
|
||||||
page: 2,
|
page: 2,
|
||||||
size: 2,
|
size: 2,
|
||||||
});
|
});
|
||||||
@@ -390,6 +426,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
{
|
{
|
||||||
asset: 'USD',
|
asset: 'USD',
|
||||||
totalAmount: '200',
|
totalAmount: '200',
|
||||||
|
decimals: 6,
|
||||||
rewardTypes: {
|
rewardTypes: {
|
||||||
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||||
amount: '0',
|
amount: '0',
|
||||||
@@ -421,4 +458,69 @@ describe('generateEpochIndividualRewardsList', () => {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('correctly calculates the percentage of two or more rewards by referencing the total rewards amount', () => {
|
||||||
|
const result = generateEpochIndividualRewardsList({
|
||||||
|
rewards: [
|
||||||
|
// reward1 is 100 usd, which is 10% of the total rewards amount
|
||||||
|
reward1,
|
||||||
|
{
|
||||||
|
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
|
||||||
|
amount: '200',
|
||||||
|
percentageOfTotal: '0.2',
|
||||||
|
receivedAt: new Date(),
|
||||||
|
asset: { id: 'usd', symbol: 'USD', name: 'USD', decimals: 6 },
|
||||||
|
party: { id: 'blah' },
|
||||||
|
epoch: { id: '1' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
epochId: 1,
|
||||||
|
epochRewardSummaries: [
|
||||||
|
{
|
||||||
|
__typename: 'EpochRewardSummary',
|
||||||
|
epoch: 1,
|
||||||
|
assetId: 'usd',
|
||||||
|
amount: '1000',
|
||||||
|
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result[0]).toEqual({
|
||||||
|
epoch: 1,
|
||||||
|
rewards: [
|
||||||
|
{
|
||||||
|
asset: 'USD',
|
||||||
|
decimals: 6,
|
||||||
|
totalAmount: '300',
|
||||||
|
rewardTypes: {
|
||||||
|
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||||
|
amount: '0',
|
||||||
|
percentageOfTotal: '0',
|
||||||
|
},
|
||||||
|
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
|
||||||
|
amount: '0',
|
||||||
|
percentageOfTotal: '0',
|
||||||
|
},
|
||||||
|
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
|
||||||
|
amount: '300',
|
||||||
|
percentageOfTotal: '30',
|
||||||
|
},
|
||||||
|
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
|
||||||
|
amount: '0',
|
||||||
|
percentageOfTotal: '0',
|
||||||
|
},
|
||||||
|
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
|
||||||
|
amount: '0',
|
||||||
|
percentageOfTotal: '0',
|
||||||
|
},
|
||||||
|
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
|
||||||
|
amount: '0',
|
||||||
|
percentageOfTotal: '0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+30
-11
@@ -1,6 +1,9 @@
|
|||||||
import { BigNumber } from '../../../lib/bignumber';
|
import { BigNumber } from '../../../lib/bignumber';
|
||||||
import { RowAccountTypes } from '../shared-rewards-table-assets/shared-rewards-table-assets';
|
import { RowAccountTypes } from '../shared-rewards-table-assets/shared-rewards-table-assets';
|
||||||
import type { RewardFieldsFragment } from '../home/__generated__/Rewards';
|
import type {
|
||||||
|
EpochRewardSummaryFieldsFragment,
|
||||||
|
RewardFieldsFragment,
|
||||||
|
} from '../home/__generated__/Rewards';
|
||||||
import type { AccountType } from '@vegaprotocol/types';
|
import type { AccountType } from '@vegaprotocol/types';
|
||||||
import { calculateEpochOffset } from '../../../lib/epoch-pagination';
|
import { calculateEpochOffset } from '../../../lib/epoch-pagination';
|
||||||
|
|
||||||
@@ -9,6 +12,7 @@ export interface EpochIndividualReward {
|
|||||||
rewards: {
|
rewards: {
|
||||||
asset: string;
|
asset: string;
|
||||||
totalAmount: string;
|
totalAmount: string;
|
||||||
|
decimals: number;
|
||||||
rewardTypes: {
|
rewardTypes: {
|
||||||
[key in AccountType]?: {
|
[key in AccountType]?: {
|
||||||
amount: string;
|
amount: string;
|
||||||
@@ -31,11 +35,13 @@ const emptyRowAccountTypes = accountTypes.map((type) => [
|
|||||||
export const generateEpochIndividualRewardsList = ({
|
export const generateEpochIndividualRewardsList = ({
|
||||||
rewards,
|
rewards,
|
||||||
epochId,
|
epochId,
|
||||||
|
epochRewardSummaries,
|
||||||
page = 1,
|
page = 1,
|
||||||
size = 10,
|
size = 10,
|
||||||
}: {
|
}: {
|
||||||
rewards: RewardFieldsFragment[];
|
rewards: RewardFieldsFragment[];
|
||||||
epochId: number;
|
epochId: number;
|
||||||
|
epochRewardSummaries: EpochRewardSummaryFieldsFragment[];
|
||||||
page?: number;
|
page?: number;
|
||||||
size?: number;
|
size?: number;
|
||||||
}) => {
|
}) => {
|
||||||
@@ -53,6 +59,8 @@ export const generateEpochIndividualRewardsList = ({
|
|||||||
const epochIndividualRewards = rewards.reduce((acc, reward) => {
|
const epochIndividualRewards = rewards.reduce((acc, reward) => {
|
||||||
const epochId = reward.epoch.id;
|
const epochId = reward.epoch.id;
|
||||||
const assetName = reward.asset.name;
|
const assetName = reward.asset.name;
|
||||||
|
const assetId = reward.asset.id;
|
||||||
|
const assetDecimals = reward.asset.decimals;
|
||||||
const rewardType = reward.rewardType;
|
const rewardType = reward.rewardType;
|
||||||
const amount = reward.amount;
|
const amount = reward.amount;
|
||||||
const percentageOfTotal = reward.percentageOfTotal;
|
const percentageOfTotal = reward.percentageOfTotal;
|
||||||
@@ -68,11 +76,20 @@ export const generateEpochIndividualRewardsList = ({
|
|||||||
|
|
||||||
const epoch = acc.get(epochId);
|
const epoch = acc.get(epochId);
|
||||||
|
|
||||||
|
// matchingTotalReward is the total awarded for all users for the reward type in the epoch of the asset
|
||||||
|
const matchingTotalRewardAmount = epochRewardSummaries.find(
|
||||||
|
(summary) =>
|
||||||
|
summary.epoch === Number(epochId) &&
|
||||||
|
summary.assetId === assetId &&
|
||||||
|
summary.rewardType === rewardType
|
||||||
|
)?.amount;
|
||||||
|
|
||||||
let asset = epoch?.rewards.find((r) => r.asset === assetName);
|
let asset = epoch?.rewards.find((r) => r.asset === assetName);
|
||||||
|
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
asset = {
|
asset = {
|
||||||
asset: assetName,
|
asset: assetName,
|
||||||
|
decimals: assetDecimals,
|
||||||
totalAmount: '0',
|
totalAmount: '0',
|
||||||
rewardTypes: Object.fromEntries(emptyRowAccountTypes),
|
rewardTypes: Object.fromEntries(emptyRowAccountTypes),
|
||||||
};
|
};
|
||||||
@@ -83,22 +100,24 @@ export const generateEpochIndividualRewardsList = ({
|
|||||||
asset.rewardTypes[rewardType] = { amount, percentageOfTotal };
|
asset.rewardTypes[rewardType] = { amount, percentageOfTotal };
|
||||||
} else {
|
} else {
|
||||||
const previousAmount = asset.rewardTypes[rewardType]?.amount;
|
const previousAmount = asset.rewardTypes[rewardType]?.amount;
|
||||||
const previousPercentageOfTotal =
|
const newAmount = previousAmount
|
||||||
asset.rewardTypes[rewardType]?.percentageOfTotal;
|
? new BigNumber(previousAmount).plus(amount).toString()
|
||||||
|
: amount;
|
||||||
|
|
||||||
asset.rewardTypes[rewardType] = {
|
asset.rewardTypes[rewardType] = {
|
||||||
amount: previousAmount
|
amount: newAmount,
|
||||||
? new BigNumber(previousAmount).plus(amount).toString()
|
percentageOfTotal: matchingTotalRewardAmount
|
||||||
: amount,
|
? new BigNumber(newAmount)
|
||||||
percentageOfTotal: previousPercentageOfTotal
|
.dividedBy(matchingTotalRewardAmount)
|
||||||
? new BigNumber(previousPercentageOfTotal)
|
.multipliedBy(100)
|
||||||
.plus(percentageOfTotal)
|
|
||||||
.toString()
|
.toString()
|
||||||
: percentageOfTotal,
|
: // this should never be reached, if there's an individual reward there should
|
||||||
|
// always be a reward total from the api too, but set it as a fallback just in case
|
||||||
|
percentageOfTotal,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// totalAmount is the sum of all rewardTypes amounts
|
// totalAmount is the sum of all individual rewardTypes amounts
|
||||||
asset.totalAmount = Object.values(asset.rewardTypes).reduce(
|
asset.totalAmount = Object.values(asset.rewardTypes).reduce(
|
||||||
(sum, rewardType) => {
|
(sum, rewardType) => {
|
||||||
return new BigNumber(sum).plus(rewardType.amount).toString();
|
return new BigNumber(sum).plus(rewardType.amount).toString();
|
||||||
|
|||||||
+1
@@ -52,6 +52,7 @@ const assetRewards: Map<
|
|||||||
assetRewards.set(assetId, {
|
assetRewards.set(assetId, {
|
||||||
assetId,
|
assetId,
|
||||||
name: 'tDAI TEST',
|
name: 'tDAI TEST',
|
||||||
|
decimals: 6,
|
||||||
rewards,
|
rewards,
|
||||||
totalAmount: '295',
|
totalAmount: '295',
|
||||||
});
|
});
|
||||||
|
|||||||
+29
-12
@@ -1,6 +1,5 @@
|
|||||||
import { formatNumber, toBigNum } from '@vegaprotocol/utils';
|
import { formatNumber, toBigNum } from '@vegaprotocol/utils';
|
||||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useAppState } from '../../../contexts/app-state/app-state-context';
|
|
||||||
import {
|
import {
|
||||||
rowGridItemStyles,
|
rowGridItemStyles,
|
||||||
RewardsTable,
|
RewardsTable,
|
||||||
@@ -12,16 +11,19 @@ interface EpochTotalRewardsGridProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface RewardItemProps {
|
interface RewardItemProps {
|
||||||
value: string;
|
amount: string;
|
||||||
|
decimals: number;
|
||||||
dataTestId: string;
|
dataTestId: string;
|
||||||
last?: boolean;
|
last?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DisplayReward = ({ reward }: { reward: string }) => {
|
const DisplayReward = ({
|
||||||
const {
|
reward,
|
||||||
appState: { decimals },
|
decimals,
|
||||||
} = useAppState();
|
}: {
|
||||||
|
reward: string;
|
||||||
|
decimals: number;
|
||||||
|
}) => {
|
||||||
if (Number(reward) === 0) {
|
if (Number(reward) === 0) {
|
||||||
return <span className="text-vega-dark-300">-</span>;
|
return <span className="text-vega-dark-300">-</span>;
|
||||||
}
|
}
|
||||||
@@ -33,11 +35,16 @@ const DisplayReward = ({ reward }: { reward: string }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const RewardItem = ({ value, dataTestId, last }: RewardItemProps) => (
|
const RewardItem = ({
|
||||||
|
amount,
|
||||||
|
decimals,
|
||||||
|
dataTestId,
|
||||||
|
last,
|
||||||
|
}: RewardItemProps) => (
|
||||||
<div data-testid={dataTestId} className={rowGridItemStyles(last)}>
|
<div data-testid={dataTestId} className={rowGridItemStyles(last)}>
|
||||||
<div className="h-full w-5 absolute right-0 top-0 bg-gradient-to-r from-transparent to-black pointer-events-none" />
|
<div className="h-full w-5 absolute right-0 top-0 bg-gradient-to-r from-transparent to-black pointer-events-none" />
|
||||||
<div className="overflow-auto p-5">
|
<div className="overflow-auto p-5">
|
||||||
<DisplayReward reward={value} />
|
<DisplayReward reward={amount} decimals={decimals} />
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full w-5 absolute left-0 top-0 bg-gradient-to-l from-transparent to-black pointer-events-none" />
|
<div className="h-full w-5 absolute left-0 top-0 bg-gradient-to-l from-transparent to-black pointer-events-none" />
|
||||||
</div>
|
</div>
|
||||||
@@ -49,15 +56,25 @@ export const EpochTotalRewardsTable = ({
|
|||||||
return (
|
return (
|
||||||
<RewardsTable dataTestId="epoch-total-rewards-table" epoch={data.epoch}>
|
<RewardsTable dataTestId="epoch-total-rewards-table" epoch={data.epoch}>
|
||||||
{Array.from(data.assetRewards.values()).map(
|
{Array.from(data.assetRewards.values()).map(
|
||||||
({ name, rewards, totalAmount }, i) => (
|
({ name, rewards, totalAmount, decimals }, i) => (
|
||||||
<div className="contents" key={i}>
|
<div className="contents" key={i}>
|
||||||
<div data-testid="asset" className={`${rowGridItemStyles()} p-5`}>
|
<div data-testid="asset" className={`${rowGridItemStyles()} p-5`}>
|
||||||
{name}
|
{name}
|
||||||
</div>
|
</div>
|
||||||
{Array.from(rewards.values()).map(({ rewardType, amount }, i) => (
|
{Array.from(rewards.values()).map(({ rewardType, amount }, i) => (
|
||||||
<RewardItem key={i} dataTestId={rewardType} value={amount} />
|
<RewardItem
|
||||||
|
key={i}
|
||||||
|
dataTestId={rewardType}
|
||||||
|
amount={amount}
|
||||||
|
decimals={decimals}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
<RewardItem dataTestId="total" value={totalAmount} last={true} />
|
<RewardItem
|
||||||
|
dataTestId="total"
|
||||||
|
amount={totalAmount}
|
||||||
|
decimals={decimals}
|
||||||
|
last={true}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|||||||
+21
@@ -56,12 +56,14 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
node: {
|
node: {
|
||||||
id: '1',
|
id: '1',
|
||||||
name: 'Asset 1',
|
name: 'Asset 1',
|
||||||
|
decimals: 18,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: {
|
node: {
|
||||||
id: '2',
|
id: '2',
|
||||||
name: 'Asset 2',
|
name: 'Asset 2',
|
||||||
|
decimals: 6,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -101,6 +103,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
{
|
{
|
||||||
node: {
|
node: {
|
||||||
epoch: 1,
|
epoch: 1,
|
||||||
|
decimals: 18,
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
|
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
|
||||||
amount: '123',
|
amount: '123',
|
||||||
@@ -128,6 +131,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
'1',
|
'1',
|
||||||
{
|
{
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 0,
|
||||||
name: '',
|
name: '',
|
||||||
rewards: new Map([
|
rewards: new Map([
|
||||||
[
|
[
|
||||||
@@ -196,12 +200,14 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
node: {
|
node: {
|
||||||
id: '1',
|
id: '1',
|
||||||
name: 'Asset 1',
|
name: 'Asset 1',
|
||||||
|
decimals: 18,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: {
|
node: {
|
||||||
id: '2',
|
id: '2',
|
||||||
name: 'Asset 2',
|
name: 'Asset 2',
|
||||||
|
decimals: 6,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -212,6 +218,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
node: {
|
node: {
|
||||||
epoch: 1,
|
epoch: 1,
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
rewardType: AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
|
rewardType: AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
|
||||||
amount: '123',
|
amount: '123',
|
||||||
},
|
},
|
||||||
@@ -220,6 +227,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
node: {
|
node: {
|
||||||
epoch: 1,
|
epoch: 1,
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
rewardType: AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE,
|
rewardType: AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE,
|
||||||
amount: '100',
|
amount: '100',
|
||||||
},
|
},
|
||||||
@@ -228,6 +236,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
node: {
|
node: {
|
||||||
epoch: 2,
|
epoch: 2,
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
|
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
|
||||||
amount: '5',
|
amount: '5',
|
||||||
},
|
},
|
||||||
@@ -254,6 +263,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
'1',
|
'1',
|
||||||
{
|
{
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
name: 'Asset 1',
|
name: 'Asset 1',
|
||||||
rewards: new Map([
|
rewards: new Map([
|
||||||
[
|
[
|
||||||
@@ -319,6 +329,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
'1',
|
'1',
|
||||||
{
|
{
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
name: 'Asset 1',
|
name: 'Asset 1',
|
||||||
rewards: new Map([
|
rewards: new Map([
|
||||||
[
|
[
|
||||||
@@ -387,12 +398,14 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
node: {
|
node: {
|
||||||
id: '1',
|
id: '1',
|
||||||
name: 'Asset 1',
|
name: 'Asset 1',
|
||||||
|
decimals: 18,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: {
|
node: {
|
||||||
id: '2',
|
id: '2',
|
||||||
name: 'Asset 2',
|
name: 'Asset 2',
|
||||||
|
decimals: 6,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -403,6 +416,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
node: {
|
node: {
|
||||||
epoch: 1,
|
epoch: 1,
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
rewardType: AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
|
rewardType: AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
|
||||||
amount: '123',
|
amount: '123',
|
||||||
},
|
},
|
||||||
@@ -411,6 +425,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
node: {
|
node: {
|
||||||
epoch: 1,
|
epoch: 1,
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
rewardType: AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE,
|
rewardType: AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE,
|
||||||
amount: '100',
|
amount: '100',
|
||||||
},
|
},
|
||||||
@@ -419,6 +434,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
node: {
|
node: {
|
||||||
epoch: 2,
|
epoch: 2,
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
|
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
|
||||||
amount: '6',
|
amount: '6',
|
||||||
},
|
},
|
||||||
@@ -427,6 +443,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
node: {
|
node: {
|
||||||
epoch: 2,
|
epoch: 2,
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
|
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
|
||||||
amount: '27',
|
amount: '27',
|
||||||
},
|
},
|
||||||
@@ -435,6 +452,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
node: {
|
node: {
|
||||||
epoch: 3,
|
epoch: 3,
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
rewardType: AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE,
|
rewardType: AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE,
|
||||||
amount: '15',
|
amount: '15',
|
||||||
},
|
},
|
||||||
@@ -467,6 +485,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
{
|
{
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
name: 'Asset 1',
|
name: 'Asset 1',
|
||||||
|
decimals: 18,
|
||||||
rewards: new Map([
|
rewards: new Map([
|
||||||
[
|
[
|
||||||
AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
|
AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
|
||||||
@@ -531,6 +550,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
'1',
|
'1',
|
||||||
{
|
{
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
name: 'Asset 1',
|
name: 'Asset 1',
|
||||||
rewards: new Map([
|
rewards: new Map([
|
||||||
[
|
[
|
||||||
@@ -608,6 +628,7 @@ describe('generateEpochAssetRewardsList', () => {
|
|||||||
'1',
|
'1',
|
||||||
{
|
{
|
||||||
assetId: '1',
|
assetId: '1',
|
||||||
|
decimals: 18,
|
||||||
name: 'Asset 1',
|
name: 'Asset 1',
|
||||||
rewards: new Map([
|
rewards: new Map([
|
||||||
[
|
[
|
||||||
|
|||||||
+2
@@ -22,6 +22,7 @@ export type AggregatedEpochRewardSummary = {
|
|||||||
name: EpochSummaryWithNamedReward['name'];
|
name: EpochSummaryWithNamedReward['name'];
|
||||||
rewards: Map<RewardType, RewardItem>;
|
rewards: Map<RewardType, RewardItem>;
|
||||||
totalAmount: string;
|
totalAmount: string;
|
||||||
|
decimals: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EpochTotalSummary = {
|
export type EpochTotalSummary = {
|
||||||
@@ -91,6 +92,7 @@ export const generateEpochTotalRewardsList = ({
|
|||||||
assetId: reward.assetId,
|
assetId: reward.assetId,
|
||||||
name: matchingAsset?.name || '',
|
name: matchingAsset?.name || '',
|
||||||
rewards: rewards || new Map(emptyRowAccountTypes),
|
rewards: rewards || new Map(emptyRowAccountTypes),
|
||||||
|
decimals: matchingAsset?.decimals || 0,
|
||||||
totalAmount: (
|
totalAmount: (
|
||||||
Number(reward.amount) + Number(assetWithRewards?.totalAmount || 0)
|
Number(reward.amount) + Number(assetWithRewards?.totalAmount || 0)
|
||||||
).toString(),
|
).toString(),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ fragment RewardFields on Reward {
|
|||||||
id
|
id
|
||||||
symbol
|
symbol
|
||||||
name
|
name
|
||||||
|
decimals
|
||||||
}
|
}
|
||||||
party {
|
party {
|
||||||
id
|
id
|
||||||
@@ -21,6 +22,13 @@ fragment DelegationFields on Delegation {
|
|||||||
epoch
|
epoch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fragment EpochRewardSummaryFields on EpochRewardSummary {
|
||||||
|
epoch
|
||||||
|
assetId
|
||||||
|
amount
|
||||||
|
rewardType
|
||||||
|
}
|
||||||
|
|
||||||
query Rewards(
|
query Rewards(
|
||||||
$partyId: ID!
|
$partyId: ID!
|
||||||
$fromEpoch: Int
|
$fromEpoch: Int
|
||||||
@@ -49,13 +57,16 @@ query Rewards(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
epochRewardSummaries(
|
||||||
|
filter: { fromEpoch: $fromEpoch, toEpoch: $toEpoch }
|
||||||
fragment EpochRewardSummaryFields on EpochRewardSummary {
|
pagination: $rewardsPagination
|
||||||
epoch
|
) {
|
||||||
assetId
|
edges {
|
||||||
amount
|
node {
|
||||||
rewardType
|
...EpochRewardSummaryFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query EpochAssetsRewards(
|
query EpochAssetsRewards(
|
||||||
@@ -67,6 +78,7 @@ query EpochAssetsRewards(
|
|||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
decimals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ import * as Types from '@vegaprotocol/types';
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import * as Apollo from '@apollo/client';
|
import * as Apollo from '@apollo/client';
|
||||||
const defaultOptions = {} as const;
|
const defaultOptions = {} as const;
|
||||||
export type RewardFieldsFragment = { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string, name: string }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } };
|
export type RewardFieldsFragment = { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } };
|
||||||
|
|
||||||
export type DelegationFieldsFragment = { __typename?: 'Delegation', amount: string, epoch: number };
|
export type DelegationFieldsFragment = { __typename?: 'Delegation', amount: string, epoch: number };
|
||||||
|
|
||||||
|
export type EpochRewardSummaryFieldsFragment = { __typename?: 'EpochRewardSummary', epoch: number, assetId: string, amount: string, rewardType: Types.AccountType };
|
||||||
|
|
||||||
export type RewardsQueryVariables = Types.Exact<{
|
export type RewardsQueryVariables = Types.Exact<{
|
||||||
partyId: Types.Scalars['ID'];
|
partyId: Types.Scalars['ID'];
|
||||||
fromEpoch?: Types.InputMaybe<Types.Scalars['Int']>;
|
fromEpoch?: Types.InputMaybe<Types.Scalars['Int']>;
|
||||||
@@ -16,9 +18,7 @@ export type RewardsQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type RewardsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, rewardsConnection?: { __typename?: 'RewardsConnection', edges?: Array<{ __typename?: 'RewardEdge', node: { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string, name: string }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } } } | null> | null } | null, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number } } | null> | null } | null } | null };
|
export type RewardsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, rewardsConnection?: { __typename?: 'RewardsConnection', edges?: Array<{ __typename?: 'RewardEdge', node: { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } } } | null> | null } | null, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number } } | null> | null } | null } | null, epochRewardSummaries?: { __typename?: 'EpochRewardSummaryConnection', edges?: Array<{ __typename?: 'EpochRewardSummaryEdge', node: { __typename?: 'EpochRewardSummary', epoch: number, assetId: string, amount: string, rewardType: Types.AccountType } } | null> | null } | null };
|
||||||
|
|
||||||
export type EpochRewardSummaryFieldsFragment = { __typename?: 'EpochRewardSummary', epoch: number, assetId: string, amount: string, rewardType: Types.AccountType };
|
|
||||||
|
|
||||||
export type EpochAssetsRewardsQueryVariables = Types.Exact<{
|
export type EpochAssetsRewardsQueryVariables = Types.Exact<{
|
||||||
epochRewardSummariesFilter?: Types.InputMaybe<Types.RewardSummaryFilter>;
|
epochRewardSummariesFilter?: Types.InputMaybe<Types.RewardSummaryFilter>;
|
||||||
@@ -26,7 +26,7 @@ export type EpochAssetsRewardsQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type EpochAssetsRewardsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string } } | null> | null } | null, epochRewardSummaries?: { __typename?: 'EpochRewardSummaryConnection', edges?: Array<{ __typename?: 'EpochRewardSummaryEdge', node: { __typename?: 'EpochRewardSummary', epoch: number, assetId: string, amount: string, rewardType: Types.AccountType } } | null> | null } | null };
|
export type EpochAssetsRewardsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, decimals: number } } | null> | null } | null, epochRewardSummaries?: { __typename?: 'EpochRewardSummaryConnection', edges?: Array<{ __typename?: 'EpochRewardSummaryEdge', node: { __typename?: 'EpochRewardSummary', epoch: number, assetId: string, amount: string, rewardType: Types.AccountType } } | null> | null } | null };
|
||||||
|
|
||||||
export type EpochFieldsFragment = { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } };
|
export type EpochFieldsFragment = { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } };
|
||||||
|
|
||||||
@@ -42,6 +42,7 @@ export const RewardFieldsFragmentDoc = gql`
|
|||||||
id
|
id
|
||||||
symbol
|
symbol
|
||||||
name
|
name
|
||||||
|
decimals
|
||||||
}
|
}
|
||||||
party {
|
party {
|
||||||
id
|
id
|
||||||
@@ -101,9 +102,20 @@ export const RewardsDocument = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
epochRewardSummaries(
|
||||||
|
filter: {fromEpoch: $fromEpoch, toEpoch: $toEpoch}
|
||||||
|
pagination: $rewardsPagination
|
||||||
|
) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
...EpochRewardSummaryFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
${RewardFieldsFragmentDoc}
|
${RewardFieldsFragmentDoc}
|
||||||
${DelegationFieldsFragmentDoc}`;
|
${DelegationFieldsFragmentDoc}
|
||||||
|
${EpochRewardSummaryFieldsFragmentDoc}`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __useRewardsQuery__
|
* __useRewardsQuery__
|
||||||
@@ -143,6 +155,7 @@ export const EpochAssetsRewardsDocument = gql`
|
|||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
decimals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
|
|||||||
import { DocsLinks } from '@vegaprotocol/environment';
|
import { DocsLinks } from '@vegaprotocol/environment';
|
||||||
import { ConnectToSeeRewards } from '../connect-to-see-rewards';
|
import { ConnectToSeeRewards } from '../connect-to-see-rewards';
|
||||||
import { EpochTotalRewards } from '../epoch-total-rewards/epoch-total-rewards';
|
import { EpochTotalRewards } from '../epoch-total-rewards/epoch-total-rewards';
|
||||||
|
import { usePreviousEpochQuery } from '../../staking/__generated__/PreviousEpoch';
|
||||||
|
import { getMultisigStatusInfo } from '../../../lib/get-multisig-status-info';
|
||||||
|
import { MultisigIncorrectNotice } from '../../../components/multisig-incorrect-notice';
|
||||||
|
|
||||||
type RewardsView = 'total' | 'individual';
|
type RewardsView = 'total' | 'individual';
|
||||||
|
|
||||||
@@ -41,12 +44,25 @@ export const RewardsPage = () => {
|
|||||||
|
|
||||||
useRefreshAfterEpoch(epochData?.epoch.timestamps.expiry, refetch);
|
useRefreshAfterEpoch(epochData?.epoch.timestamps.expiry, refetch);
|
||||||
|
|
||||||
|
const { data: previousEpochData } = usePreviousEpochQuery({
|
||||||
|
variables: {
|
||||||
|
epochId: (Number(epochData?.epoch.id) - 1).toString(),
|
||||||
|
},
|
||||||
|
skip: !epochData?.epoch.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const multisigStatus = previousEpochData
|
||||||
|
? getMultisigStatusInfo(previousEpochData)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
params,
|
params,
|
||||||
loading: paramsLoading,
|
loading: paramsLoading,
|
||||||
error: paramsError,
|
error: paramsError,
|
||||||
} = useNetworkParams([NetworkParams.reward_staking_delegation_payoutDelay]);
|
} = useNetworkParams([NetworkParams.reward_staking_delegation_payoutDelay]);
|
||||||
|
|
||||||
|
console.log('params', params);
|
||||||
|
|
||||||
const payoutDuration = useMemo(() => {
|
const payoutDuration = useMemo(() => {
|
||||||
if (!params) {
|
if (!params) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -78,14 +94,18 @@ export const RewardsPage = () => {
|
|||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{payoutDuration ? (
|
{multisigStatus?.showMultisigStatusError ? (
|
||||||
|
<MultisigIncorrectNotice />
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{!multisigStatus?.showMultisigStatusError && payoutDuration ? (
|
||||||
<div className="my-8">
|
<div className="my-8">
|
||||||
<Callout
|
<Callout
|
||||||
title={t('rewardsCallout', {
|
title={t('rewardsCallout', {
|
||||||
duration: formatDistance(new Date(0), payoutDuration),
|
duration: formatDistance(new Date(0), payoutDuration),
|
||||||
})}
|
})}
|
||||||
headingLevel={3}
|
headingLevel={3}
|
||||||
intent={Intent.Warning}
|
intent={Intent.Primary}
|
||||||
>
|
>
|
||||||
<p className="mb-0">{t('rewardsCalloutDetail')}</p>
|
<p className="mb-0">{t('rewardsCalloutDetail')}</p>
|
||||||
</Callout>
|
</Callout>
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { ValidatorTables } from './validator-tables';
|
|||||||
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
|
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { ENV } from '../../../config';
|
import { ENV } from '../../../config';
|
||||||
|
import { getMultisigStatusInfo } from '../../../lib/get-multisig-status-info';
|
||||||
|
import { MultisigIncorrectNotice } from '../../../components/multisig-incorrect-notice';
|
||||||
|
|
||||||
export const EpochData = () => {
|
export const EpochData = () => {
|
||||||
// errorPolicy due to vegaprotocol/vega issue 5898
|
// errorPolicy due to vegaprotocol/vega issue 5898
|
||||||
@@ -46,12 +48,20 @@ export const EpochData = () => {
|
|||||||
userStakingRefetch();
|
userStakingRefetch();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const multisigStatus = previousEpochData
|
||||||
|
? getMultisigStatusInfo(previousEpochData)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer
|
<AsyncRenderer
|
||||||
loading={nodesLoading || userStakingLoading}
|
loading={nodesLoading || userStakingLoading}
|
||||||
error={nodesError || userStakingError}
|
error={nodesError || userStakingError}
|
||||||
data={nodesData}
|
data={nodesData}
|
||||||
>
|
>
|
||||||
|
{multisigStatus?.showMultisigStatusError ? (
|
||||||
|
<MultisigIncorrectNotice />
|
||||||
|
) : null}
|
||||||
|
|
||||||
{nodesData?.epoch &&
|
{nodesData?.epoch &&
|
||||||
nodesData.epoch.timestamps.start &&
|
nodesData.epoch.timestamps.start &&
|
||||||
nodesData?.epoch.timestamps.expiry && (
|
nodesData?.epoch.timestamps.expiry && (
|
||||||
|
|||||||
+8
@@ -36,6 +36,7 @@ import {
|
|||||||
toBigNum,
|
toBigNum,
|
||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import { VALIDATOR_LOGO_MAP } from './logo-map';
|
import { VALIDATOR_LOGO_MAP } from './logo-map';
|
||||||
|
import { getMultisigStatusInfo } from '../../../../lib/get-multisig-status-info';
|
||||||
|
|
||||||
interface CanonisedConsensusNodeProps {
|
interface CanonisedConsensusNodeProps {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -137,6 +138,10 @@ export const ConsensusValidatorsTable = ({
|
|||||||
[totalStake]
|
[totalStake]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const multisigStatus = previousEpochData
|
||||||
|
? getMultisigStatusInfo(previousEpochData)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const allNodesInPreviousEpoch = removePaginationWrapper(
|
const allNodesInPreviousEpoch = removePaginationWrapper(
|
||||||
previousEpochData?.epoch.validatorsConnection?.edges
|
previousEpochData?.epoch.validatorsConnection?.edges
|
||||||
);
|
);
|
||||||
@@ -223,6 +228,8 @@ export const ConsensusValidatorsTable = ({
|
|||||||
[ValidatorFields.USER_STAKE_SHARE]: userStakeShare
|
[ValidatorFields.USER_STAKE_SHARE]: userStakeShare
|
||||||
? formatNumberPercentage(new BigNumber(userStakeShare), 2)
|
? formatNumberPercentage(new BigNumber(userStakeShare), 2)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
[ValidatorFields.MULTISIG_ERROR]:
|
||||||
|
multisigStatus?.showMultisigStatusError,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -332,6 +339,7 @@ export const ConsensusValidatorsTable = ({
|
|||||||
data,
|
data,
|
||||||
decimals,
|
decimals,
|
||||||
hideTopThird,
|
hideTopThird,
|
||||||
|
multisigStatus?.showMultisigStatusError,
|
||||||
previousEpochData,
|
previousEpochData,
|
||||||
thirdOfTotalStake,
|
thirdOfTotalStake,
|
||||||
validatorsView,
|
validatorsView,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export enum ValidatorFields {
|
|||||||
STAKED_BY_USER = 'stakedByUser',
|
STAKED_BY_USER = 'stakedByUser',
|
||||||
PENDING_USER_STAKE = 'pendingUserStake',
|
PENDING_USER_STAKE = 'pendingUserStake',
|
||||||
USER_STAKE_SHARE = 'userStakeShare',
|
USER_STAKE_SHARE = 'userStakeShare',
|
||||||
|
MULTISIG_ERROR = 'multisigError',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addUserDataToValidator = (
|
export const addUserDataToValidator = (
|
||||||
@@ -326,6 +327,7 @@ interface TotalPenaltiesRendererProps {
|
|||||||
overstakedAmount: string;
|
overstakedAmount: string;
|
||||||
overstakingPenalty: string;
|
overstakingPenalty: string;
|
||||||
totalPenalties: string;
|
totalPenalties: string;
|
||||||
|
multisigError?: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,10 +346,11 @@ export const TotalPenaltiesRenderer = ({
|
|||||||
<div data-testid="overstaked-penalty-tooltip">
|
<div data-testid="overstaked-penalty-tooltip">
|
||||||
{t('overstakedPenalty')}: {data.overstakingPenalty}
|
{t('overstakedPenalty')}: {data.overstakingPenalty}
|
||||||
</div>
|
</div>
|
||||||
<div data-testid="total-penalty-tooltip">
|
{data.multisigError && (
|
||||||
{t('totalPenalties')}:{' '}
|
<div data-testid="multisig-error-tooltip">
|
||||||
<span className="font-bold">{data.totalPenalties}</span>
|
{t('multisigPenalty')}: 100%
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ export const StakingNode = ({ data, previousEpochData }: StakingNodeProps) => {
|
|||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<Icon name={'chevron-left'} />
|
<Icon name={'chevron-left'} />
|
||||||
<Link className="underline" to={Routes.VALIDATORS}>
|
<Link className="underline" to={Routes.VALIDATORS}>
|
||||||
{t('All validators')}
|
{t('AllValidators')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<Heading
|
<Heading
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ NX_VEGA_ENV=DEVNET
|
|||||||
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\"}
|
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\"}
|
||||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
|
NX_VEGA_EXPLORER_URL=#
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\"}
|
|||||||
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://etherscan.io
|
NX_ETHERSCAN_URL=https://etherscan.io
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz
|
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz
|
||||||
NX_VEGA_CONSOLE_URL=https://vega.trading
|
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||||
|
|||||||
@@ -7,31 +7,30 @@ import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
|||||||
import {
|
import {
|
||||||
getFeeLevels,
|
getFeeLevels,
|
||||||
sumLiquidityCommitted,
|
sumLiquidityCommitted,
|
||||||
marketLiquidityDataProvider,
|
|
||||||
lpAggregatedDataProvider,
|
lpAggregatedDataProvider,
|
||||||
} from '@vegaprotocol/liquidity';
|
} from '@vegaprotocol/liquidity';
|
||||||
import type { MarketLpQuery } from '@vegaprotocol/liquidity';
|
import { marketWithDataProvider } from '@vegaprotocol/markets';
|
||||||
|
import type { MarketWithData } from '@vegaprotocol/markets';
|
||||||
|
|
||||||
import { Market } from './market';
|
import { Market } from './market';
|
||||||
import { Header } from './header';
|
import { Header } from './header';
|
||||||
import { LPProvidersGrid } from './providers';
|
import { LPProvidersGrid } from './providers';
|
||||||
|
|
||||||
const formatMarket = (data: MarketLpQuery) => {
|
const formatMarket = (market: MarketWithData) => {
|
||||||
return {
|
return {
|
||||||
name: data?.market?.tradableInstrument.instrument.name,
|
name: market?.tradableInstrument.instrument.name,
|
||||||
symbol:
|
symbol:
|
||||||
data?.market?.tradableInstrument.instrument.product.settlementAsset
|
market?.tradableInstrument.instrument.product.settlementAsset.symbol,
|
||||||
.symbol,
|
|
||||||
settlementAsset:
|
settlementAsset:
|
||||||
data?.market?.tradableInstrument.instrument.product.settlementAsset,
|
market?.tradableInstrument.instrument.product.settlementAsset,
|
||||||
targetStake: data?.market?.data?.targetStake,
|
targetStake: market?.data?.targetStake,
|
||||||
tradingMode: data?.market?.data?.marketTradingMode,
|
tradingMode: market?.data?.marketTradingMode,
|
||||||
trigger: data?.market?.data?.trigger,
|
trigger: market?.data?.trigger,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const lpDataProvider = makeDerivedDataProvider(
|
export const lpDataProvider = makeDerivedDataProvider(
|
||||||
[marketLiquidityDataProvider, lpAggregatedDataProvider],
|
[marketWithDataProvider, lpAggregatedDataProvider],
|
||||||
([market, lpAggregatedData]) => ({
|
([market, lpAggregatedData]) => ({
|
||||||
market: { ...formatMarket(market) },
|
market: { ...formatMarket(market) },
|
||||||
liquidityProviders: lpAggregatedData || [],
|
liquidityProviders: lpAggregatedData || [],
|
||||||
|
|||||||
@@ -3,3 +3,6 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/maste
|
|||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
NX_VEGA_NETWORKS='{"TESTNET":"https://multisig-signer.fairground.wtf","MAINNET":"https://multisig-signer.vega.xyz"}'
|
NX_VEGA_NETWORKS='{"TESTNET":"https://multisig-signer.fairground.wtf","MAINNET":"https://multisig-signer.vega.xyz"}'
|
||||||
NX_VEGA_ENV=MAINNET
|
NX_VEGA_ENV=MAINNET
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
# Static
|
# Static
|
||||||
|
|
||||||
A static CDN for Vega assets
|
A static CDN for Vega assets: `static.vega.xyz`
|
||||||
|
|
||||||
|
prepare assets by running: `yarn nx build static`
|
||||||
|
|||||||
@@ -26,27 +26,27 @@
|
|||||||
animation-direction: reverse;
|
animation-direction: reverse;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:first-child {
|
.pre-loader .loader-item:first-child {
|
||||||
animation-delay: -50ms;
|
animation-delay: -0.1s;
|
||||||
animation-direction: alternate;
|
animation-direction: alternate;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(2) {
|
.pre-loader .loader-item:nth-child(2) {
|
||||||
animation-delay: 0.2s;
|
animation-delay: 0.3s;
|
||||||
animation-direction: reverse;
|
animation-direction: reverse;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(3) {
|
.pre-loader .loader-item:nth-child(3) {
|
||||||
animation-delay: -0.6s;
|
animation-delay: -0.45s;
|
||||||
animation-direction: alternate;
|
animation-direction: alternate;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(4) {
|
.pre-loader .loader-item:nth-child(4) {
|
||||||
animation-delay: 0.4s;
|
animation-delay: 1s;
|
||||||
animation-direction: reverse;
|
animation-direction: reverse;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(5) {
|
.pre-loader .loader-item:nth-child(5) {
|
||||||
animation-delay: -0.5s;
|
animation-delay: -0.75s;
|
||||||
animation-direction: alternate;
|
animation-direction: alternate;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(6) {
|
.pre-loader .loader-item:nth-child(6) {
|
||||||
animation-delay: 0.3s;
|
animation-delay: 0.9s;
|
||||||
animation-direction: reverse;
|
animation-direction: reverse;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(7) {
|
.pre-loader .loader-item:nth-child(7) {
|
||||||
@@ -54,11 +54,11 @@
|
|||||||
animation-direction: alternate;
|
animation-direction: alternate;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(8) {
|
.pre-loader .loader-item:nth-child(8) {
|
||||||
animation-delay: 2s;
|
animation-delay: 1.6s;
|
||||||
animation-direction: reverse;
|
animation-direction: reverse;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(9) {
|
.pre-loader .loader-item:nth-child(9) {
|
||||||
animation-delay: -0.9s;
|
animation-delay: -0.45s;
|
||||||
animation-direction: alternate;
|
animation-direction: alternate;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(10) {
|
.pre-loader .loader-item:nth-child(10) {
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
animation-direction: reverse;
|
animation-direction: reverse;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(11) {
|
.pre-loader .loader-item:nth-child(11) {
|
||||||
animation-delay: -0.55s;
|
animation-delay: -2.75s;
|
||||||
animation-direction: alternate;
|
animation-direction: alternate;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(12) {
|
.pre-loader .loader-item:nth-child(12) {
|
||||||
@@ -74,21 +74,57 @@
|
|||||||
animation-direction: reverse;
|
animation-direction: reverse;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(13) {
|
.pre-loader .loader-item:nth-child(13) {
|
||||||
animation-delay: -0.65s;
|
animation-delay: -1.95s;
|
||||||
animation-direction: alternate;
|
animation-direction: alternate;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(14) {
|
.pre-loader .loader-item:nth-child(14) {
|
||||||
animation-delay: 0.7s;
|
animation-delay: 2.8s;
|
||||||
animation-direction: reverse;
|
animation-direction: reverse;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(15) {
|
.pre-loader .loader-item:nth-child(15) {
|
||||||
animation-delay: -3.75s;
|
animation-delay: -0.75s;
|
||||||
animation-direction: alternate;
|
animation-direction: alternate;
|
||||||
}
|
}
|
||||||
.pre-loader .loader-item:nth-child(16) {
|
.pre-loader .loader-item:nth-child(16) {
|
||||||
animation-delay: 1.6s;
|
animation-delay: 4s;
|
||||||
animation-direction: reverse;
|
animation-direction: reverse;
|
||||||
}
|
}
|
||||||
|
.pre-loader .loader-item:nth-child(17) {
|
||||||
|
animation-delay: -0.85s;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
.pre-loader .loader-item:nth-child(18) {
|
||||||
|
animation-delay: 1.8s;
|
||||||
|
animation-direction: reverse;
|
||||||
|
}
|
||||||
|
.pre-loader .loader-item:nth-child(19) {
|
||||||
|
animation-delay: -1.9s;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
.pre-loader .loader-item:nth-child(20) {
|
||||||
|
animation-delay: 5s;
|
||||||
|
animation-direction: reverse;
|
||||||
|
}
|
||||||
|
.pre-loader .loader-item:nth-child(21) {
|
||||||
|
animation-delay: -5.25s;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
.pre-loader .loader-item:nth-child(22) {
|
||||||
|
animation-delay: 4.4s;
|
||||||
|
animation-direction: reverse;
|
||||||
|
}
|
||||||
|
.pre-loader .loader-item:nth-child(23) {
|
||||||
|
animation-delay: -5.75s;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
.pre-loader .loader-item:nth-child(24) {
|
||||||
|
animation-delay: 4.8s;
|
||||||
|
animation-direction: reverse;
|
||||||
|
}
|
||||||
|
.pre-loader .loader-item:nth-child(25) {
|
||||||
|
animation-delay: -5s;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
.pre-loader .loader-item {
|
.pre-loader .loader-item {
|
||||||
animation: flickering 0.4s linear infinite alternate;
|
animation: flickering 0.4s linear infinite alternate;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
.pre-loader {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
.loader-item {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
.pre-loader-center {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.pre-loader-wrapper {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
@for $i from 0 through 25 {
|
||||||
|
.loader-item:nth-child(#{$i}) {
|
||||||
|
@if $i % 2 == 0 {
|
||||||
|
animation-delay: #{$i * 50 * random(5)}ms;
|
||||||
|
animation-direction: reverse;
|
||||||
|
} @else {
|
||||||
|
animation-delay: #{$i * -50 * random(5)}ms;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.loader-item {
|
||||||
|
animation: flickering 0.4s linear alternate infinite;
|
||||||
|
}
|
||||||
|
@keyframes flickering {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
26% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html.dark {
|
||||||
|
.pre-loader {
|
||||||
|
.loader-item {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ NX_VEGA_WALLET_URL=http://localhost:1789
|
|||||||
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
|
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
|
||||||
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
|
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
|
||||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||||
|
NX_SENTRY_DSN=https://dummy@o999999.ingest.sentry.io/9999999
|
||||||
|
|
||||||
# Expose some env vars to cypress environment for market setup
|
# Expose some env vars to cypress environment for market setup
|
||||||
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
||||||
|
|||||||
@@ -0,0 +1,177 @@
|
|||||||
|
// #region consts
|
||||||
|
const assetColId = '[col-id="asset.symbol"]';
|
||||||
|
const assetDetailsDialog = 'dialog-content';
|
||||||
|
const assetRow = 'key-value-table-row';
|
||||||
|
const contractAddress = '7_value';
|
||||||
|
const dialogCloseBtn = 'close-asset-details-dialog';
|
||||||
|
const dialogCloseX = 'dialog-close';
|
||||||
|
const dialogTitle = 'dialog-title';
|
||||||
|
|
||||||
|
const indicesWithLabelTooltips = [4, 5, 6, 7, 8, 9, 11, 12, 13, 14];
|
||||||
|
const indicesWithValueTooltips = [1, 6];
|
||||||
|
|
||||||
|
const labelValueToolTipPairs = [
|
||||||
|
{
|
||||||
|
label: 'ID',
|
||||||
|
value: 'asset-id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Type',
|
||||||
|
value: 'ERC20',
|
||||||
|
valueToolTip: 'An asset originated from an Ethereum ERC20 Token',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Name',
|
||||||
|
value: 'Euro',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Symbol',
|
||||||
|
value: 'tEURO',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Decimals',
|
||||||
|
value: '5',
|
||||||
|
labelTooltip: 'Number of decimal / precision handled by this asset',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Quantum',
|
||||||
|
value: '0.00001',
|
||||||
|
labelTooltip: 'The minimum economically meaningful amount of the asset',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Status',
|
||||||
|
value: 'Enabled',
|
||||||
|
labelTooltip: 'The status of the asset in the Vega network',
|
||||||
|
valueToolTip: 'Asset can be used on the Vega network',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Contract address',
|
||||||
|
value: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4 ',
|
||||||
|
labelTooltip:
|
||||||
|
'The address of the contract for the token, on the ethereum network',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Withdrawal threshold',
|
||||||
|
value: '0.0005',
|
||||||
|
labelTooltip:
|
||||||
|
"The maximum you can withdraw instantly. There's no limit on the size of a withdrawal, but all withdrawals over the threshold will have a delay time added to them",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Lifetime limit',
|
||||||
|
value: '1,230.00',
|
||||||
|
labelTooltip:
|
||||||
|
'The lifetime deposit limit per address. Note: this is a temporary measure that can be changed or removed through governance',
|
||||||
|
},
|
||||||
|
{ label: '', value: '' },
|
||||||
|
{
|
||||||
|
label: 'Infrastructure fee account balance',
|
||||||
|
value: '0.00001',
|
||||||
|
labelTooltip: 'The infrastructure fee account in this asset',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Global reward pool account balance',
|
||||||
|
value: '0.00002',
|
||||||
|
labelTooltip: 'The global rewards acquired in this asset',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Maker paid fees account balance',
|
||||||
|
value: '0.00003',
|
||||||
|
labelTooltip:
|
||||||
|
'The rewards acquired based on the fees paid to makers in this asset',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Maker received fees account balance',
|
||||||
|
value: '0.00004',
|
||||||
|
labelTooltip:
|
||||||
|
'The rewards acquired based on fees received for being a maker on trades',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Liquidity provision fee reward account balance',
|
||||||
|
value: '0.00005',
|
||||||
|
labelTooltip:
|
||||||
|
'The rewards acquired based on the liquidity provision fees in this asset',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Market proposer reward account balance',
|
||||||
|
value: '0.00006',
|
||||||
|
labelTooltip:
|
||||||
|
'The rewards acquired based on the market proposer reward in this asset',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.mockTradingPage();
|
||||||
|
cy.mockSubscription();
|
||||||
|
cy.setVegaWallet();
|
||||||
|
});
|
||||||
|
|
||||||
|
const visitPortfolioAndClickAsset = (assetName: string) => {
|
||||||
|
cy.visit('/#/portfolio');
|
||||||
|
cy.get(assetColId).contains(assetName).click();
|
||||||
|
};
|
||||||
|
|
||||||
|
const testTooltip = (index: number, testId: string, tooltip: string) => {
|
||||||
|
cy.getByTestId(`${index}_${testId}`).realHover();
|
||||||
|
cy.get('[role="tooltip"]').find('div').should('have.text', tooltip);
|
||||||
|
cy.getByTestId(dialogTitle).click();
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('assets', { tags: '@smoke', testIsolation: true }, () => {
|
||||||
|
it('asset details', () => {
|
||||||
|
visitPortfolioAndClickAsset('tBTC');
|
||||||
|
|
||||||
|
cy.getByTestId(assetRow).each((element, index) => {
|
||||||
|
if (index === 10) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { label, value, labelTooltip, valueToolTip } =
|
||||||
|
labelValueToolTipPairs[index];
|
||||||
|
// 6501-ASSE-001
|
||||||
|
// 6501-ASSE-002
|
||||||
|
// 6501-ASSE-003
|
||||||
|
// 6501-ASSE-004
|
||||||
|
// 6501-ASSE-005
|
||||||
|
// 6501-ASSE-006
|
||||||
|
// 6501-ASSE-007
|
||||||
|
// 6501-ASSE-008
|
||||||
|
// 6501-ASSE-009
|
||||||
|
// 6501-ASSE-010
|
||||||
|
// 6501-ASSE-011
|
||||||
|
cy.getByTestId(`${index}_label`).should('have.text', label);
|
||||||
|
cy.getByTestId(`${index}_value`).should('have.text', value);
|
||||||
|
|
||||||
|
// 6501-ASSE-012
|
||||||
|
if (indicesWithLabelTooltips.includes(index)) {
|
||||||
|
if (labelTooltip) {
|
||||||
|
testTooltip(index, 'label', labelTooltip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (indicesWithValueTooltips.includes(index)) {
|
||||||
|
if (valueToolTip) {
|
||||||
|
testTooltip(index, 'value', valueToolTip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 6501-ASSE-013
|
||||||
|
cy.getByTestId(dialogCloseX).click();
|
||||||
|
cy.document().then((doc) => {
|
||||||
|
expect(doc.querySelector(assetDetailsDialog)).to.not.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ERC20 Contract address', () => {
|
||||||
|
visitPortfolioAndClickAsset('tBTC');
|
||||||
|
cy.getByTestId(contractAddress).within(() => {
|
||||||
|
// 6501-ASSE-014
|
||||||
|
cy.getByTestId('external-link')
|
||||||
|
.should('have.attr', 'target', '_blank')
|
||||||
|
.should('have.text', '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4');
|
||||||
|
});
|
||||||
|
// 6501-ASSE-013
|
||||||
|
cy.getByTestId(dialogCloseBtn).click();
|
||||||
|
cy.document().then((doc) => {
|
||||||
|
expect(doc.querySelector(assetDetailsDialog)).to.not.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user