Compare commits

..
Author SHA1 Message Date
JonRay15 ba0af64bef Merge branch 'develop' into JonRay15-patch-2 2023-08-02 12:28:09 +01:00
JonRay15 be4fb779ef Update feature-epic.md 2023-08-02 12:26:40 +01:00
JonRay15 f2eedc434d Update feature-epic.md 2023-08-02 12:02:21 +01:00
m.ray fde49e5446 fix(trading): order stopped misleading message (#4455) 2023-08-02 11:52:07 +01:00
JonRay15andMatthew Russell 45283161aa chore: create feature-epic issue template (#4456)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-08-02 11:48:23 +01:00
Matthew Russell 4eacbbba1c chore: add default title 2023-08-02 11:47:59 +01:00
Bartłomiej GłowniaandDariusz Majcherczyk 375d447fa8 feat(trading): add stop orders table and form (#4265)
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
2023-08-02 11:28:33 +01:00
Mikołaj Młodzikowski 1dd97a2bce feat(ci): add develop docker image (#4458) 2023-08-02 10:58:17 +02:00
JonRay15 e9188344cf Update feature-epic.md 2023-08-01 23:24:24 +01:00
JonRay15 16c18b972d Create feature-epic.md 2023-08-01 23:11:15 +01:00
Edd d4a1a9b193 fix(explorer): add tests and fix transactions url generation (#4454) 2023-08-01 16:35:40 +01:00
Edd 376c5241a8 feat(explorer): improve transaction pagination (#4435) 2023-08-01 14:41:16 +00:00
Ciaran McGhie 8e6d8517cf feat(ui-toolkit,tailwindcss-config): healthbar auction level indicator (#4406) 2023-08-01 09:44:03 +01:00
Matthew Russell 5f9ec222c1 feat(trading): navigation (#4375) 2023-07-31 17:08:55 +01:00
Edd 8954c41c0a fix(governance): remove incorrect individual reward percentage (#4443) 2023-07-31 15:23:52 +00:00
Mikołaj Młodzikowski 4414ab4f47 feat(ci): wait for publish job to complete via github API 2023-07-31 15:04:34 +02:00
Mikołaj Młodzikowski d1d4bacc68 feat(ci): patch mainnet release 2023-07-31 13:09:00 +02:00
Joe Tsang f476688c7f chore(governance): fix failing proposal test (#4434) 2023-07-31 09:58:52 +01:00
Sam Keen 8845222700 feat(governance): remove max limit on associate function (#4427) 2023-07-28 11:12:29 +00:00
Radosław Szpiech e64c464091 chore(trading): move cumulative vol testid in orderbook (#4420) 2023-07-28 11:15:40 +02:00
Joe Tsang b2c2d0d7d6 test(governance): add e2e test and acs for proposal enhancements (#4421) 2023-07-28 09:34:39 +01:00
Joe Tsang 1fb61d313c chore(governance): add acs for network upgrade banner and estimate (#4402) 2023-07-28 09:34:30 +01:00
Mikołaj Młodzikowski ccf5ff632c feat(ci): setup new tests for console (#4400) 2023-07-28 07:32:07 +02:00
Maciek 54d6aaf56f feat(trading): add market successor proposal banner (#4401) 2023-07-27 14:54:00 +00:00
Mikołaj Młodzikowski 736b262947 fix(ci): publish of static dist (#4414) 2023-07-27 13:52:00 +02:00
Sam KeenandMatthew Russell 6a07127185 feat(governance): diff highlighter for update market proposals (#4260)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-07-27 11:26:32 +01:00
Sam Keen 45f0ba7c0e fix(explorer): explorer validator page filtering (#4354) 2023-07-27 09:04:54 +00:00
John WalleyandMatthew Russell 6f4ea68778 chore(trading): upgrade pennant to v1.10.0 (#4331)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-07-26 15:35:57 +01:00
Mikołaj Młodzikowski 90dda20891 feat(ci): migrate ci-cd trigger to python (#4330) 2023-07-26 16:08:57 +02:00
Art 278eb01c2f feat(governance): successor market proposal details (#4393) 2023-07-26 14:52:12 +02:00
Sam Keen c3157de146 fix(governance): removed icons test from proposal list item details (#4392) 2023-07-25 15:59:58 +00:00
d28db485c5 chore(trading): market relationship - parent market in proposals list (#4339)
Co-authored-by: asiaznik <artur@vegaprotocol.io>
Co-authored-by: Edd <edd@vega.xyz>
2023-07-25 15:32:40 +00:00
Maciek caa0076396 fix(deal-ticket): 4046 wrong margin requirement in order (#4378) 2023-07-25 14:52:32 +00:00
Edd 451da40ed2 feat(explorer): iceberg details on order tx (#4380) 2023-07-25 13:34:04 +00:00
Joe Tsang 47694e7b72 chore(explorer): explorer market e2e test (#4355) 2023-07-25 11:25:37 +01:00
Sam Keen e01fb7f9ae feat(governance): proposal list tile and summary enhancements (#4326) 2023-07-25 11:23:25 +01:00
Joe Tsang ffcdfb6a6a chore(governance): add e2e test for network upgrade banner (#4361) 2023-07-25 10:48:59 +01:00
Joe Tsang 86f0d013bb chore(governance): minor fixes to flaky nightly tests (#4335) 2023-07-25 10:48:49 +01:00
ArtandEdd c12ac45890 feat(environment): feature flags (#4343)
Co-authored-by: Edd <edd@vega.xyz>
2023-07-25 11:12:53 +02:00
47ce68455a chore(trading): fix flakey trading-trades test (#4363)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
Co-authored-by: Art <artur@vegaprotocol.io>
Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
2023-07-24 16:41:44 +01:00
c1675e4b49 feat(trading): design changes (#4264)
Co-authored-by: Art <artur@vegaprotocol.io>
Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
2023-07-24 09:37:18 +01:00
Matthew Russell f8c4d39b93 fix(positions): fix valueGetter for realisedPNL in positions table 2023-07-20 17:55:21 +01:00
Matthew Russell e55cf5ecc6 chore(trading): cherry pick position pnl formatting fix (#4347) 2023-07-20 12:52:33 +01:00
Matthew Russell 406cf22810 chore(trading): remove user pnl from closed market list (#4312) 2023-07-20 12:52:13 +01:00
Edd 8ff46bab5b fix(explorer): fix valueformatter in enactment date on proposal table (#4358) 2023-07-20 10:52:49 +02:00
Art 5f177785b6 feat(governance): protocol upgrade notification, est. time (#4289) 2023-07-20 10:27:43 +02:00
Mikołaj Młodzikowski 06779f36ca feat(ci): fix typo 2023-07-19 16:42:47 +02:00
Sam Keen 29991015b5 fix(governance): filtered out nodes with 0 performance score from homepage list (#4267) 2023-07-19 13:32:57 +01:00
Matthew Russell 071a6ff8bb chore(explorer): clear out slack webhook (#4320) 2023-07-19 11:36:34 +01:00
5b8df4c414 chore(trading): orderbook adjustments (#4293)
Co-authored-by: Ben <ben@vega.xyz>
Co-authored-by: Mikołaj Młodzikowski <mikolaj.mlodzikowski@gmail.com>
Co-authored-by: Joe Tsang <30622993+jtsang586@users.noreply.github.com>
Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com>
Co-authored-by: m.ray <16125548+MadalinaRaicu@users.noreply.github.com>
Co-authored-by: Art <artur@vegaprotocol.io>
Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
Co-authored-by: Gordsport <83510148+gordsport@users.noreply.github.com>
2023-07-18 14:48:51 +00:00
Daniel ce6873fe54 feat(environment): add mainnet mirror config (#4287) 2023-07-18 12:23:58 +01:00
Gordsport d0e64364e3 chore: update the PM action secret token (#4325) 2023-07-18 12:16:57 +01:00
Bartłomiej Głownia 737ffb4c35 feat(trading): copy order book volume value to deal ticket (#4333) 2023-07-18 12:16:07 +01:00
Maciek 53048ac8ef chore(trading): 4134 see if a closed market was succeeded (#4336) 2023-07-18 09:37:25 +00:00
Art 05ca1a09b9 chore(explorer): align staking terminology (#4290) 2023-07-18 09:03:48 +00:00
m.ray 94e398dd1c feat(trading): submit iceberg orders (#4230) 2023-07-17 14:24:51 +00:00
m.ray 7c0a4f61e9 fix(trading): add internal termination oracle (#4208) 2023-07-17 13:33:52 +00:00
m.ray 056d3215e8 feat(trading): view iceberg orders (#4207) 2023-07-17 13:04:03 +00:00
Dexter Edwards a68b2093e4 fix(ui-toolkit): toolkit bugs (#4329) 2023-07-17 10:59:22 +00:00
Mikołaj Młodzikowski f440f57be2 fix(ci): do not trigger releasing to s3 on pull requests 2023-07-14 13:45:06 +02:00
Mikołaj Młodzikowski edbdbcf38e feat(ci): provide fixes for releasing individual apps 2023-07-13 16:10:07 +02:00
Mikołaj Młodzikowski 94a067e34b fix(ci): disable pull_request_target (#4315) 2023-07-13 11:19:37 +02:00
Joe Tsang 8b6b904cd6 test(governance): un-skip governance tests (#4292) 2023-07-13 10:10:48 +01:00
Mikołaj Młodzikowski 27cd8086e1 fix(ci): syntax on switch case 2023-07-12 17:47:46 +02:00
Mikołaj Młodzikowski 6aa109131e feat(ci): allow individual releases of the applications (#4300) 2023-07-12 17:37:49 +02:00
Ben 74777e54f9 chore(ci): revert run console-test on CICD (#4303) 2023-07-12 16:26:52 +01:00
Ben 61e7450906 feat(trading): run console-test on CICD (#4271) 2023-07-12 12:06:48 +01:00
Matthew Russell 6a55319e04 feat(trading,governance,wallet): browser wallet integration (#4121) 2023-07-12 11:34:42 +01:00
Matthew Russell 5692d4e74c Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into develop 2023-07-12 11:01:22 +01:00
Maciek ffe89d0fe0 feat(trading): add market banner for successor markets (#4269) 2023-07-12 11:20:01 +02:00
Matthew Russell 57e1ecac6c chore(trading): release v0.20.21-core-0.71.6 2023-07-12 09:01:59 +01:00
daro-maj 77e1390686 test(trading): fix capsule place order test (#4286) 2023-07-12 08:54:40 +01:00
Matthew Russell 981c8649a2 fix(trading): replace oracle details and deal ticket pink with red (#4284) 2023-07-11 14:26:24 +01:00
Bartłomiej Głownia 501ffbfc80 chore(trading): ignore parse source map warnings, fix trading readme (#4252) 2023-07-11 10:41:54 +01:00
Mikołaj Młodzikowski f391e8c351 fix(ci): add different settings to curl and print preview link 2023-07-10 15:53:38 +02:00
Edd 0e10b2108e chore(explorer): update block explorer types for 72 (#4275) 2023-07-10 14:12:12 +01:00
Bartłomiej Głownia 162a934408 feat(trading): amend market red and green colors (#4226) 2023-07-07 14:52:38 +02:00
Joe Tsang 4581e117c4 test(cypress): clean up nx todos (#4273) 2023-07-07 09:23:27 +01:00
Bartłomiej Głownia e89b818e4c feat(orders): reduce number of columns in orders table (#4238) 2023-07-06 17:57:29 +02:00
daro-maj 0665ac85db test(trading): add withdrawal delayed (#4268) 2023-07-06 15:49:02 +02:00
Joe Tsang 3c71a86b48 chore(governance): skip test (#4263) 2023-07-06 09:40:57 +01:00
Art b381f16ace fix(announcements): remember dismissed announcement (#4255) 2023-07-05 16:59:22 +02:00
Matthew Russellandsam-keen fc6ce9e99b fix(governance,trading): proposals not showing (#4222)
Co-authored-by: sam-keen <samuel.kleinmann@gmail.com>
2023-07-05 14:09:13 +01:00
Art f6fc4df1c5 chore(trading): dropdown alignments, account history default asset, transfer dialog asset selector (#4239) 2023-07-05 13:02:02 +02:00
Art fc8f12d6fc fix(proposals): truncated text in network param toast (#4249) 2023-07-05 12:50:42 +02:00
Gordsport 26f4c1c983 feat(governance,explorer,trading): add env config for mainnet-mirror apps (#4253) 2023-07-04 16:20:40 +00:00
Maciek efd632f5c6 chore(orders): get rid of unnecessary stores (#4231) 2023-07-04 17:47:04 +02:00
Joe Tsang ce3da1762b chore(governance): add e2e test for proposal filter changes (#4218) 2023-07-04 13:27:12 +01:00
John Walley 5040fbfd07 chore(trading): upgrade pennant to v1.9.0 (#4235) 2023-07-04 12:10:38 +00:00
Edd 74f2cfa4a5 feat(explorer): remove infinite tx loader (#4217) 2023-07-04 12:51:28 +01:00
Art 8c8fe6878a chore(wallet): remove links from the risk disclaimer (#4240) 2023-07-04 12:12:38 +01:00
Bartłomiej Głownia 6e0577aee4 chore(trading): migrate nx to latest version (#4196) 2023-07-04 13:01:25 +02:00
783 changed files with 23083 additions and 15061 deletions
+1
View File
@@ -0,0 +1 @@
node_modules
+13 -7
View File
@@ -1,7 +1,7 @@
{
"root": true,
"ignorePatterns": ["**/*"],
"plugins": ["@nrwl/nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"],
"plugins": ["@nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"],
"settings": {
"jsx-a11y": {
"components": {
@@ -18,7 +18,7 @@
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"extends": ["plugin:jsx-a11y/strict"],
"rules": {
"@nrwl/nx/enforce-module-boundaries": [
"@nx/enforce-module-boundaries": [
"error",
{
"enforceBuildableLibDependency": true,
@@ -51,12 +51,13 @@
"ul": ["list"],
"ol": ["list"]
}
]
],
"no-console": ["error", { "allow": ["warn", "error"] }]
}
},
{
"files": ["*.ts", "*.tsx"],
"extends": ["plugin:@nrwl/nx/typescript"],
"extends": ["plugin:@nx/typescript"],
"rules": {
"@typescript-eslint/ban-ts-comment": [
"error",
@@ -80,14 +81,19 @@
},
{
"files": ["*.spec.ts", "*.spec.tsx"],
"extends": ["plugin:@nrwl/nx/typescript", "plugin:jest/recommended"],
"extends": ["plugin:@nx/typescript", "plugin:jest/recommended"],
"rules": {
"jest/consistent-test-it": ["error", { "fn": "it" }]
"jest/consistent-test-it": [
"error",
{
"fn": "it"
}
]
}
},
{
"files": ["*.js", "*.jsx"],
"extends": ["plugin:@nrwl/nx/javascript"],
"extends": ["plugin:@nx/javascript"],
"rules": {}
}
]
+29
View File
@@ -0,0 +1,29 @@
---
name: Feature Epic
about:
A template to capture and scope user requirements, high level process, and basic mockups for an upcoming feature as part of the initial core spec review process.
title: 'Epic: '
labels: feature-epic
---
## Core Feature
<Name>
## Tasks
- [ ] Define high level requirements
- [ ] Create basic mockups
- [ ] Update "API Requirements" in core spec
- [ ] Update "User-Interface Spec" in relevant front end repo
- [ ] Create detailed user stories using normal template
## High Level Requirements
## Basic Mockups
## Link to API Requirements in Core spec
## Link to User Interface Specs
## Linked User Stories
@@ -7,7 +7,7 @@ on:
jobs:
after-release:
runs-on: ubuntu-22.04
timeout-minutes: 30
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -30,18 +30,20 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Wait for publish to complete
uses: lewagon/wait-on-check-action@v1.3.1
with:
ref: ${{ github.event.release.tag_name }}
check-name: '(CD) publish dist / trading'
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 10
- name: resolve ipfs hashes for release
run: |
echo "Name: ${{ github.event.release.name }}"
echo "Description: ${{ github.event.release.body }}"
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"
sleep 60
done
docker run --rm vegaprotocol/trading:$commit cat /ipfs-hash > ipfs-hash
docker run --rm vegaprotocol/trading:mainnet 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
tar -xzf kubo.tgz
export PATH="$PATH:$PWD/kubo"
+1 -1
View File
@@ -6,7 +6,7 @@ name: 'Add Issues To Project Board'
types:
- opened
env:
GH_TOKEN: ${{ secrets.GH_NEW_CARD_TO_PROJECT }}
GH_TOKEN: ${{ secrets.PROJECT_MANAGE_ACTION }}
PROJECT_ID: ${{ secrets.FRONT_END_PROJECT_ID }}
ISSUE_ID: ${{ github.event.issue.node_id }}
USER: ${{ github.actor }}
+38 -110
View File
@@ -5,10 +5,7 @@ on:
branches:
- release/*
- develop
- main
# uncomment pull_request and comment pull_request_target to test CI changes against feature branch not target branch (develop)
# pull_request:
pull_request_target:
pull_request:
types:
- opened
- ready_for_review
@@ -49,7 +46,7 @@ jobs:
lint-pr-title:
needs: node-modules
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
if: ${{ github.event_name == 'pull_request' }}
name: Verify PR title
uses: ./.github/workflows/lint-pr.yml
secrets: inherit
@@ -84,6 +81,22 @@ jobs:
with:
main-branch-name: develop
# See affected apps
- name: See affected apps
run: |
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
python3 tools/ci/check-affected.py --github-ref="${{ github.ref }}" --branch-slug="$branch_slug" --event-name="${{ github.event_name }}"
- name: Verify script result
run: |
echo "Check outputs from script"
echo "projects: ${{ env.PROJECTS }}"
echo "projects-e2e: ${{ env.PROJECTS_E2E }}"
echo "preview_governance: ${{ env.PREVIEW_GOVERNANCE }}"
echo "preview_trading: ${{ env.PREVIEW_TRADING }}"
echo "preview_explorer: ${{ env.PREVIEW_EXPLORER }}"
echo "preview_tools: ${{ env.PREVIEW_TOOLS }}"
- name: Check formatting
run: yarn nx format:check
@@ -99,100 +112,6 @@ jobs:
- name: Build affected
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
# See affected apps
- name: See affected apps
run: |
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)"
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
echo ">>>> debug"
echo "NX_BASE: ${{ env.NX_BASE }}"
echo "NX_HEAD: ${{ env.NX_HEAD }}"
echo "Affected: ${affected}"
echo "Branch slug: ${branch_slug}"
echo ">>>> eof debug"
projects_array=()
preview_governance="not deployed"
preview_trading="not deployed"
preview_explorer="not deployed"
preview_tools="not deployed"
# 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")
fi
if echo "$affected" | grep -q trading; then
echo "Trading is affected"
projects_array+=("trading")
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
fi
if echo "$affected" | grep -q explorer; then
echo "Explorer is affected"
projects_array+=("explorer")
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
fi
if [[ ${#projects_array[@]} -eq 0 ]]; then
projects_array=("governance" "trading" "explorer")
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
fi
# applications parsed before this loop are applicable for running e2e-tests
projects_e2e_array=()
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_TRADING=$preview_trading >> $GITHUB_ENV
echo PREVIEW_EXPLORER=$preview_explorer >> $GITHUB_ENV
echo PREVIEW_TOOLS=$preview_tools >> $GITHUB_ENV
outputs:
projects: ${{ env.PROJECTS }}
projects-e2e: ${{ env.PROJECTS_E2E }}
@@ -201,6 +120,15 @@ jobs:
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
preview_tools: ${{ env.PREVIEW_TOOLS }}
console-e2e:
needs: lint-test-build
name: '(CI) console python'
uses: ./.github/workflows/console-test-run.yml
secrets: inherit
if: ${{ contains(fromJSON(needs.lint-test-build.outputs.projects), 'trading') && github.event_name == 'pull_request' }}
with:
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
cypress:
needs: lint-test-build
name: '(CI) cypress'
@@ -214,7 +142,7 @@ jobs:
publish-dist:
needs: lint-test-build
name: '(CD) publish dist'
# if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo') || github.event_name == 'push' }}
uses: ./.github/workflows/publish-dist.yml
secrets: inherit
with:
@@ -225,7 +153,7 @@ jobs:
needs:
- publish-dist
- lint-test-build
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }}
timeout-minutes: 60
name: '(CD) comment preview links'
steps:
@@ -241,26 +169,26 @@ jobs:
# 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"
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do
echo "waiting for governance preview: ${{ needs.lint-test-build.outputs.preview_governance }}"
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"
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do
echo "waiting for explorer preview: ${{ needs.lint-test-build.outputs.preview_explorer }}"
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"
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do
echo "waiting for trading preview: ${{ needs.lint-test-build.outputs.preview_trading }}"
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"
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do
echo "waiting for tools preview: ${{ needs.lint-test-build.outputs.preview_tools }}"
sleep 5
done
fi
@@ -271,7 +199,7 @@ jobs:
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
Previews:
Previews
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
+142
View File
@@ -0,0 +1,142 @@
name: (CI) Console tests
on:
workflow_call:
inputs:
github-sha:
required: true
type: string
jobs:
run-tests:
name: run-tests
runs-on: ubuntu-22.04
timeout-minutes: 25
steps:
#----------------------------------------------
# check-out frontend-monorepo
#----------------------------------------------
- name: Checkout console test repo
uses: actions/checkout@v3
with:
ref: ${{ inputs.github-sha }}
#----------------------------------------------
# cache node modules
#----------------------------------------------
- name: Cache node modules
id: cache
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
# comment out "restore-keys" if you need to rebuild yarn from 0
restore-keys: |
${{ runner.os }}-cache-node-modules-
#----------------------------------------------
# setup node
#----------------------------------------------
- name: Setup node
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
cache: yarn
#----------------------------------------------
# install deps if cache missing
#----------------------------------------------
- name: yarn install
if: steps.cache.outputs.cache-hit != 'true'
run: yarn install --pure-lockfile
#----------------------------------------------
# build trading
#----------------------------------------------
- name: Build affected spec
run: |
yarn env-cmd -f ./apps/trading/.env.stagnet1 yarn nx export trading
#----------------------------------------------
# run trading server
#----------------------------------------------
- name: Run trading server
run: |
docker run -d -p 80:4200 -v $PWD/docker/nginx.conf:/etc/nginx/conf.d/default.conf -v $PWD/dist/apps/trading/exported:/usr/share/nginx/html nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
sleep 5
docker ps
#----------------------------------------------
# check if container persists between runs
#----------------------------------------------
- name: Check server
run: |
docker ps
#----------------------------------------------
# check-out tests repo
#----------------------------------------------
- name: Checkout console test repo
uses: actions/checkout@v3
with:
repository: vegaprotocol/console-test
path: './console-test'
#----------------------------------------------
# set-up python
#----------------------------------------------
- name: Set up python
id: setup-python
uses: actions/setup-python@v4
with:
python-version: '3.10.11'
#----------------------------------------------
# ----- install & configure poetry -----
#----------------------------------------------
- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-create: true
virtualenvs-in-project: true
virtualenvs-path: console-test/.venv
#----------------------------------------------
# load cached venv if cache exists
#----------------------------------------------
- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v3
with:
path: console-test/.venv
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}
#----------------------------------------------
# install dependencies if cache does not exist
#----------------------------------------------
- name: Install dependencies
working-directory: ./console-test
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction --no-root
#----------------------------------------------
# install vega binaries
#----------------------------------------------
- name: Install vega binaries
working-directory: ./console-test
run: poetry run python -m vega_sim.tools.load_binaries --force
#----------------------------------------------
# install playwright
#----------------------------------------------
- name: install playwright
run: poetry run playwright install
working-directory: ./console-test
#----------------------------------------------
# run tests
#----------------------------------------------
- name: Run tests
working-directory: ./console-test
run: poetry run pytest --numprocesses auto
- name: Check files
run: |
ls -al .
ls -al console-test
#----------------------------------------------
# upload traces
#----------------------------------------------
- name: Upload Playwright Trace
uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-trace
path: ./traces/
retention-days: 15
+71 -67
View File
@@ -22,6 +22,45 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Init variables
run: |
echo IS_PR=false >> $GITHUB_ENV
echo IS_MAINNET_RELEASE=false >> $GITHUB_ENV
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
echo IS_S3_RELEASE=false >> $GITHUB_ENV
echo IS_DEV_IMAGE=false >> $GITHUB_ENV
- name: Is dev image
if: ${{ contains(github.ref, 'develop') && github.event_name == 'push' && matrix.app == 'trading' }}
run: |
echo IS_DEV_IMAGE=true >> $GITHUB_ENV
- name: Is PR
if: ${{ github.event_name == 'pull_request' }}
run: |
echo IS_PR=true >> $GITHUB_ENV
- name: Is mainnet release
if: ${{ contains(github.ref, 'release/mainnet') && !contains(github.ref, 'mirror') }}
run: |
echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV
- name: Is testnet release
if: ${{ contains(github.ref, 'release/testnet') }}
run: |
echo IS_TESTNET_RELEASE=true >> $GITHUB_ENV
- name: Is IPFS Release
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( env.IS_MAINNET_RELEASE == 'true' || env.IS_TESTNET_RELEASE == 'true' ) }}
run: |
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
- name: Is S3 Release
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' }}
run: |
echo IS_S3_RELEASE=true >> $GITHUB_ENV
- name: Set up QEMU
id: quemu
uses: docker/setup-qemu-action@v2
@@ -33,7 +72,7 @@ jobs:
uses: docker/setup-buildx-action@v2
- name: Log in to the Container registry (ghcr)
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
if: ${{ env.IS_PR == 'true' }}
uses: docker/login-action@v2
with:
registry: ghcr.io
@@ -42,9 +81,8 @@ jobs:
- name: Log in to the Container registry (docker hub)
uses: docker/login-action@v2
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
with:
# registry: registry.hub.docker.com
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -65,67 +103,33 @@ jobs:
- name: Define dist variables
if: ${{ github.event_name == 'push' }}
run: |
envName=''
domain="vega.rocks"
bucketName=''
python3 tools/ci/define-dist-variables.py --github-ref="${{ github.ref }}" --app="${{ matrix.app }}"
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
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
envName="mainnet"
fi
if [[ "${envName}" = "mainnet" ]]; then
domain="vega.xyz"
if [[ -z "${bucketName}" ]]; then
bucketName="${{ matrix.app }}.${domain}"
fi
elif [[ "${envName}" = "testnet" ]]; then
domain="fairground.wtf"
if [[ -z "${bucketName}" ]]; then
bucketName="${{ matrix.app }}.${domain}"
fi
fi
if [[ -z "${bucketName}" ]]; then
bucketName="${{ matrix.app }}.${envName}.${domain}"
fi
echo "bucket name: ${bucketName}"
echo "env name: ${envName}"
echo BUCKET_NAME=${bucketName} >> $GITHUB_ENV
echo ENV_NAME=${envName} >> $GITHUB_ENV
- name: Verify script result
if: ${{ github.event_name == 'push' }}
run: |
echo "BUCKET_NAME=${{ env.BUCKET_NAME }}"
echo "ENV_NAME=${{ env.ENV_NAME }}"
- name: Build local dist
run: |
flags=""
envCmd=""
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
flags="--env=${{ env.ENV_NAME }}"
envCmd="yarn env-cmd -f ./apps/${{ matrix.app }}/.env.${{ env.ENV_NAME }}"
fi
if [ "${{ matrix.app }}" = "trading" ]; then
yarn nx export trading $flags || (yarn install && yarn nx export trading $flags)
$envCmd yarn nx export trading || (yarn install && $envCmd yarn nx export trading)
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
elif [ "${{ matrix.app }}" = "static" ]; then
yarn nx build static || (yarn install && yarn nx build static)
else
yarn nx build ${{ matrix.app }} $flags || (yarn install && yarn nx build ${{ matrix.app }} $flags)
$envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }})
fi
if [[ -z "$DIST_LOCATION" ]]; then
DIST_LOCATION=dist/apps/${{ matrix.app }}
fi
mv $DIST_LOCATION dist-result
@@ -145,7 +149,7 @@ jobs:
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
- name: Image digest
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
if: ${{ env.IS_PR == 'true' }}
run: echo ${{ steps.docker_build.outputs.digest }}
- name: Sanity check docker image
@@ -160,7 +164,7 @@ jobs:
uses: docker/build-push-action@v3
continue-on-error: true
id: ghcr-push
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
if: ${{ env.IS_PR == 'true' }}
with:
context: .
file: docker/node-outside-docker.Dockerfile
@@ -175,7 +179,7 @@ jobs:
uses: docker/build-push-action@v3
continue-on-error: true
id: dockerhub-push
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
with:
context: .
file: docker/node-outside-docker.Dockerfile
@@ -185,7 +189,7 @@ jobs:
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' || '' }}
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || '' }}
- name: Publish dist as docker image (ghcr - retry)
uses: docker/build-push-action@v3
@@ -212,13 +216,13 @@ jobs:
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' || '' }}
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
# bucket creation in github.com/vegaprotocol/terraform//frontend
- name: Publish dist to s3
uses: jakejarvis/s3-sync-action@master
# 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') ) ) ) }}
if: ${{ env.IS_S3_RELEASE == 'true' }}
with:
args: --acl private --follow-symlinks --delete
env:
@@ -229,11 +233,11 @@ jobs:
SOURCE_DIR: 'dist-result'
- name: Install aws CLI
if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
if: ${{ env.IS_S3_RELEASE == 'true' }}
uses: unfor19/install-aws-cli-action@master
- name: Perform cache invalidation
if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
if: ${{ env.IS_S3_RELEASE == 'true' }}
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
@@ -246,16 +250,16 @@ jobs:
- name: Add preview label
uses: actions-ecosystem/action-add-labels@v1
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
if: ${{ env.IS_PR == 'true' }}
with:
labels: ${{ matrix.app }}-preview
number: ${{ github.event.number }}
- name: Trigger fleek deployment
# 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') ) }}
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
run: |
if echo ${{ github.ref }} | grep -q main; then
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
# display info about app
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
-H "Content-Type: application/json" \
@@ -268,7 +272,7 @@ jobs:
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
https://api.fleek.co/graphql
elif echo ${{ github.ref }} | grep -q release/testnet; then
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
# display info about app
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
-H "Content-Type: application/json" \
@@ -283,7 +287,7 @@ jobs:
fi
- name: Check out ipfs-redirect
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
uses: actions/checkout@v3
with:
repository: 'vegaprotocol/ipfs-redirect'
@@ -292,7 +296,7 @@ jobs:
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') ) }}
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
env:
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
run: |
@@ -314,11 +318,11 @@ jobs:
git config --global user.name "vega-ci-bot"
# update CID files
if echo ${{ github.ref }} | grep -q main; then
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
echo $new_hash > cidv0-mainnet.txt
echo $new_cid > cidv1-mainnet.txt
git add cidv0-mainnet.txt cidv1-mainnet.txt
elif echo ${{ github.ref }} | grep -q release/testnet; then
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
echo $new_hash > cidv0-fairground.txt
echo $new_cid > cidv1-fairground.txt
git add cidv0-fairground.txt cidv1-fairground.txt
-29
View File
@@ -1,29 +0,0 @@
module.exports = {
stories: [],
addons: [
'@storybook/addon-actions',
'@storybook/addon-viewport',
{
name: '@storybook/addon-docs',
options: {
configureJSX: true,
babelOptions: {},
sourceLoaderOptions: null,
transcludeMarkdown: true,
},
},
'@storybook/addon-controls',
'@storybook/addon-backgrounds',
'@storybook/addon-toolbars',
'@storybook/addon-measure',
'@storybook/addon-outline',
'@storybook/addon-a11y',
],
// uncomment the property below if you want to apply some webpack config globally
// webpackFinal: async (config, { configType }) => {
// // Make whatever fine-grained changes you need that should apply to all storybook configs
// // Return the altered config
// return config;
// },
};
-14
View File
@@ -1,14 +0,0 @@
{
"extends": "../tsconfig.base.json",
"exclude": [
"../**/*.spec.js",
"../**/*.test.js",
"../**/*.spec.ts",
"../**/*.test.ts",
"../**/*.spec.tsx",
"../**/*.test.tsx",
"../**/*.spec.jsx",
"../**/*.test.jsx"
],
"include": ["../**/*"]
}
+6 -1
View File
@@ -16,5 +16,10 @@ NX_EXPLORER_NETWORK_PARAMETERS=1
NX_EXPLORER_PARTIES=1
NX_EXPLORER_VALIDATORS=1
CYPRESS_VEGA_WALLET_API_TOKEN=
CYPRESS_VEGA_URL=http://localhost:3008/graphql
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
CYPRESS_ETHEREUM_PROVIDER_URL=http://localhost:8545
CYPRESS_FAUCET_URL=http://localhost:1790/api/v1/mint
CYPRESS_VEGA_PUBLIC_KEY=02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65
CYPRESS_VEGA_WALLET_URL=http://localhost:1789
CYPRESS_VEGA_WALLET_API_TOKEN=
+4 -3
View File
@@ -1,10 +1,11 @@
{
"name": "explorer-e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/explorer-e2e/src",
"projectType": "application",
"targets": {
"e2e": {
"executor": "@nrwl/cypress:cypress",
"executor": "@nx/cypress:cypress",
"options": {
"cypressConfig": "apps/explorer-e2e/cypress.config.js",
"devServerTarget": "explorer:serve"
@@ -16,14 +17,14 @@
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"executor": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
}
},
"build": {
"executor": "@nrwl/workspace:run-commands",
"executor": "nx:run-commands",
"outputs": [],
"options": {
"command": "yarn tsc --project ./apps/explorer-e2e/"
@@ -31,7 +31,7 @@ context('Asset page', { tags: '@regression' }, () => {
});
});
it('should open details page when clicked on "View details"', () => {
it.skip('should open details page when clicked on "View details"', () => {
cy.getAssets().then((assets) => {
assets.forEach((asset) => {
cy.get(`[row-id="${asset.id}"] [col-id="actions"] button`)
+121 -10
View File
@@ -1,19 +1,130 @@
//Tests set to skip until market bug for capsule checkpoint is fixed
context.skip('Market page', { tags: '@regression' }, function () {
context('Market page', { tags: '@regression' }, function () {
describe('Verify elements on page', function () {
const marketHeaders = '[data-testid="markets-header"]';
const marketNavigation = 'a[href="/markets"]';
const marketHeaders = 'markets-heading';
const createdMarketId =
'2eab0e66545a789047561bc5a2e5cbc3b19eb708da41104e3cac2474ee36c4d4';
it('Markets page is displayed', function () {
before('Create market', function () {
cy.visit('/');
cy.get(marketNavigation).click();
cy.common_validate_blocks_data_displayed(marketHeaders);
cy.createMarket();
});
it('Markets page displayed on mobile', function () {
beforeEach('Get market id', function () {
cy.navigate_to('markets');
cy.get('[col-id="id"]').eq(1).invoke('text').as('createdMarketId');
});
it('Market displayed on market page', function () {
cy.navigate_to('markets');
cy.getByTestId(marketHeaders).should('be.visible');
cy.get(`[row-id="${this.createdMarketId}"]`)
.should('be.visible')
.within(() => {
cy.get_element_by_col_id('code').should('have.text', 'TEST.24h');
cy.get_element_by_col_id('name').should('have.text', 'Test market 1');
cy.get_element_by_col_id('state').should('have.text', 'Pending');
cy.get_element_by_col_id('asset').should('have.text', 'fUSDC');
cy.get_element_by_col_id('id').should(
'have.text',
this.createdMarketId
);
cy.get_element_by_col_id('actions')
.find('a')
.should('have.attr', 'href', `/markets/${this.createdMarketId}`);
});
});
it('Able to go to market details page', function () {
cy.navigate_to('markets');
cy.get_element_by_col_id('actions').eq(1).click();
cy.getByTestId(marketHeaders).should('have.text', 'Test market 1');
cy.validate_element_from_table('Name', 'Test market 1');
cy.validate_element_from_table('Market ID', this.createdMarketId);
cy.validate_element_from_table('Trading Mode', 'Opening auction');
cy.validate_element_from_table('Market Decimal Places', '5');
cy.validate_element_from_table('Position Decimal Places', '5');
cy.validate_element_from_table('Settlement Asset Decimal Places', '5');
// Instrument
cy.validate_element_from_table('Market Name', 'Test market 1');
cy.validate_element_from_table('Code', 'TEST.24h');
cy.validate_element_from_table('Product Type', 'Future');
cy.validate_element_from_table('Quote Name', 'fUSDC');
// Settlement Asset
cy.validate_element_from_table('Quote Name', 'fUSDC');
cy.validate_element_from_table('Symbol', 'fUSDC');
cy.validate_element_from_table('Decimals', '5');
cy.validate_element_from_table('Quantum', '0.00');
cy.validate_element_from_table('Status', 'Enabled');
cy.validate_element_from_table('Max faucet amount', '10,000,000.00');
cy.validate_element_from_table(
'Infrastructure fee account balance',
'0.00'
);
cy.validate_element_from_table(
'Global reward pool account balance',
'0.00'
);
// Metadata
cy.validate_element_from_table('Sector', 'tech');
cy.validate_element_from_table('Source', 'docs.vega.xyz');
// Risk model
cy.validate_element_from_table('Tau', '0.0001140771161');
cy.validate_element_from_table('Risk Aversion Parameter', '0.01');
// Risk parameters
// cy.validate_element_from_table('R', '0.016')
cy.validate_element_from_table('Sigma', '0.5');
// Risk factors
cy.validate_element_from_table('Short', '0.0143218738374871');
cy.validate_element_from_table('Long', '0.0141450471498822');
// Price monitoring settings 1
cy.validate_element_from_table('Horizon Secs', '43,200');
cy.validate_element_from_table('Probability', '1');
cy.validate_element_from_table('Auction Extension Secs', '600');
// Liquidity Monitoring
cy.validate_element_from_table('Triggering Ratio', '0.7');
cy.validate_element_from_table('Time Window', '3,600');
cy.validate_element_from_table('Scaling Factor', '10');
// Liquidity
cy.validate_element_from_table('Target Stake', '0.00 fUSDC');
cy.validate_element_from_table('Supplied Stake', '0.00 fUSDC');
cy.validate_element_from_table('Market Value Proxy', '0.00 fUSDC');
// Liquidity price range
cy.validate_element_from_table(
'Liquidity Price Range',
'1,000.00% of mid price'
);
cy.validate_element_from_table('Lowest Price', '0.00 fUSDC');
cy.validate_element_from_table('Highest Price', '0.00 fUSDC');
cy.getByTestId('oracle-spec-links')
.should('have.attr', 'href')
.and(
'contain',
'/oracles/bf242aa5c9f64fcbb77808aa8582e73711519f4b35264eb797a80f1803590a24'
);
// Able to view Json
cy.contains('View JSON').click();
cy.get('.language-json').should('exist');
});
// Skipping due to resize observer loop limit error
it.skip('Markets page displayed on mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(marketNavigation).click();
cy.common_validate_blocks_data_displayed(marketHeaders);
cy.navigate_to('markets', true);
cy.getByTestId(marketHeaders).should('be.visible');
cy.get(`[row-id="${createdMarketId}"]`)
.should('be.visible')
.within(() => {
cy.get_element_by_col_id('code').should('have.text', 'TEST.24h');
cy.get_element_by_col_id('name').should('have.text', 'Test market 1');
cy.get_element_by_col_id('state').should('have.text', 'Pending');
cy.get_element_by_col_id('asset').should('have.text', 'fUSDC');
cy.get_element_by_col_id('id').should('have.text', createdMarketId);
cy.get_element_by_col_id('actions')
.find('a')
.should('have.attr', 'href', `/markets/${createdMarketId}`);
});
});
});
});
@@ -169,7 +169,6 @@ context.skip('Parties page', { tags: '@regression' }, function () {
const jsonFields = '.hljs';
const sideMenuBackground = '.absolute';
// Engage dark mode if not allready set
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.then((background_color) => {
@@ -40,7 +40,7 @@ context.skip('Transactions page', function () {
.first()
.click({ force: true });
} else {
cy.slack('Unable to find any transactions on page');
cy.log('Unable to find any transactions on page');
cy.screenshot();
}
});
@@ -78,7 +78,7 @@ context.skip('Transactions page', function () {
}
});
} else {
cy.slack('Unable to find any transactions on page');
cy.log('Unable to find any transactions on page');
cy.screenshot();
}
});
@@ -7,7 +7,11 @@ context('Validator page', { tags: '@smoke' }, function () {
it('should be able to see validator tiles', function () {
cy.getNodes().then((nodes) => {
nodes.forEach((node) => {
cy.get(`[validator-id="${node.id}"]`).should('be.visible');
if (node.rankingScore.performanceScore > 0) {
cy.get(`[validator-id="${node.id}"]`).should('be.visible');
} else {
cy.get(`[validator-id="${node.id}"]`).should('not.exist');
}
});
});
});
@@ -28,7 +28,7 @@ Cypress.Commands.add('switchToMobile', () => {
Cypress.Commands.add('common_switch_to_mobile_and_click_toggle', function () {
cy.viewport('iphone-x');
cy.visit('/');
cy.get('[data-testid="open-menu"]').click();
cy.get('[data-testid="button-menu-drawer"]').click();
});
Cypress.Commands.add('monitor_clipboard', () => {
@@ -88,3 +88,42 @@ Cypress.Commands.add('convert_number_to_max_four_decimal', (number) => {
maximumFractionDigits: 4,
});
});
Cypress.Commands.add('navigate_to', (page, mobileView = false) => {
const navigation = {
transactions: '/txs',
blocks: '/blocks',
oracles: '/oracles',
validators: '/validators',
parties: '/parties',
assets: '/assets',
markets: '/markets',
governanceProposals: '/governance',
networkParameters: '/network-parameters',
genesisParameters: '/genesis',
};
const topLevelRoutes = ['transactions', 'blocks', 'oracles', 'validators'];
cy.getByTestId('navigation').within(() => {
if (!topLevelRoutes.includes(page) && mobileView === false) {
cy.getByTestId('other').first().click();
}
cy.get(`[href="${navigation[page]}"]`).first().click();
});
cy.url().should('include', navigation[page]);
});
Cypress.Commands.add('get_element_by_col_id', (elementName) => {
cy.get(`[col-id="${elementName}"]`);
});
Cypress.Commands.add(
'validate_element_from_table',
(tableRowName, tableRowValue) => {
cy.contains(tableRowName)
.parentsUntil("[data-testid='key-value-table-row']")
.siblings()
.should('have.text', tableRowValue);
}
);
+1 -1
View File
@@ -1,7 +1,7 @@
{
"presets": [
[
"@nrwl/react/babel",
"@nx/react/babel",
{
"runtime": "automatic"
}
+1 -1
View File
@@ -1,5 +1,5 @@
# App configuration variables
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/tm
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
NX_VEGA_ENV=DEVNET
+13
View File
@@ -0,0 +1,13 @@
# App configuration variables
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
NX_VEGA_ENV=MAINNET_MIRROR
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.rocks/rest
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
+2 -2
View File
@@ -1,6 +1,6 @@
{
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "__generated__"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+2 -1
View File
@@ -32,6 +32,7 @@ yarn nx serve explorer
Example configurations are provided here:
- [Mainnet](./.env.mainnet)
- [Mainnet-mirror](./.env.mainnet-mirror)
- [Devnet](./.env.devnet)
- [Capsule](./.env.capsule)
- [Testnet](./.env.testnet)
@@ -39,7 +40,7 @@ Example configurations are provided here:
For convenience, you can boot the app injecting one of the configurations above by running:
```bash
yarn nx run explorer:serve --env={env} # e.g. stagnet1
yarn env-cmd -f .\apps\explorer\.env.{env} yarn nx run explorer:serve # e.g. stagnet1
```
There are a few different configuration options offered for this app:
+2 -2
View File
@@ -4,8 +4,8 @@ export default {
displayName: 'explorer',
preset: '../../jest.preset.js',
transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
'^.+\\.[tj]sx?$': 'babel-jest',
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/apps/explorer',
+16 -9
View File
@@ -1,10 +1,11 @@
{
"name": "explorer",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/explorer/src",
"projectType": "application",
"targets": {
"build": {
"executor": "./tools/executors/webpack:build",
"executor": "@nx/webpack:webpack",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
@@ -38,7 +39,7 @@
}
},
"serve": {
"executor": "./tools/executors/webpack:serve",
"executor": "@nx/webpack:dev-server",
"options": {
"port": 3000,
"buildTarget": "explorer:build:development",
@@ -52,30 +53,36 @@
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"executor": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["coverage/apps/explorer"],
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/apps/explorer"],
"options": {
"jestConfig": "apps/explorer/jest.config.ts",
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
},
"generate-types": {
"executor": "@nrwl/workspace:run-commands",
"executor": "nx:run-commands",
"options": {
"commands": [
"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"
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/spec-update-v0.72.0-preview.2/specs/v0.72.0-preview.2/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
]
}
},
"build-netlify": {
"executor": "@nrwl/workspace:run-commands",
"executor": "nx:run-commands",
"options": {
"commands": [
"cp apps/explorer/netlify.toml netlify.toml",
@@ -84,7 +91,7 @@
}
},
"build-spec": {
"executor": "@nrwl/workspace:run-commands",
"executor": "nx:run-commands",
"outputs": [],
"options": {
"command": "yarn tsc --project ./apps/explorer/tsconfig.spec.json"
@@ -95,7 +95,10 @@ export const Header = () => {
{mainItems.map(routeToNavigationItem)}
{groupedItems && groupedItems.length > 0 && (
<NavigationItem>
<NavigationTrigger isActive={Boolean(isOnOther)}>
<NavigationTrigger
isActive={Boolean(isOnOther)}
data-testid="other"
>
{t('Other')}
</NavigationTrigger>
<NavigationContent>
@@ -137,7 +137,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
hide: window.innerWidth <= BREAKPOINT_MD,
headerName: t('Enactment date'),
field: 'terms.enactmentDatetime',
valueFormatte: ({
valueFormatter: ({
value,
}: VegaValueFormatterParams<
ProposalListFieldsFragment,
@@ -0,0 +1,52 @@
import { t } from '@vegaprotocol/i18n';
import type { components } from '../../../../../types/explorer';
import { Tooltip } from '@vegaprotocol/ui-toolkit';
export interface TxDetailsOrderIcebergDetailsProps {
iceberg: components['schemas']['v1IcebergOpts'];
size: components['schemas']['v1OrderSubmission']['size'];
}
/**
.iceberg .sub {
vertical-align: bottom;
color: #954F01;
}
.iceberg .sup {
vertical-align: top;
color: #515E1E;
}
*/
/**
* Visualises the iceberg details of an order, showing the minimum visible size,
* the full size and the peak size.
*/
export const TxOrderIcebergDetails = ({
iceberg,
size,
}: TxDetailsOrderIcebergDetailsProps) => {
return (
<div
className="inline-block iceberg bg-vega-blue-300 border-vega-blue-350 border-[1px] text-[70%] font-mono py-[2px] pl-2 pr-3 height-[1em] leading-[1em] cursor-pointer"
style={{ clipPath: 'polygon(10% 0%, 100% 0%, 90% 100%, 0% 100%)' }}
>
<Tooltip description={t('Iceberg: Minimum visible size')}>
<span className="align-bottom text-vega-orange-650">
{iceberg.minimumVisibleSize || '-'}
</span>
</Tooltip>
<Tooltip description={t('Iceberg: Total size')}>
<span className="text-sm text-vega-blue-600 mx-3">{size}</span>
</Tooltip>
<Tooltip description={t('Iceberg: Visible peak')}>
<span className="align-top text-vega-yellow-600">
{iceberg.peakSize || '-'}
</span>
</Tooltip>
</div>
);
};
@@ -6,10 +6,32 @@ import {
SPECIAL_CASE_NETWORK_ID,
} from '../../../../links/party-link/party-link';
import SizeInAsset from '../../../../size-in-asset/size-in-asset';
import { AccountTypeMapping } from '@vegaprotocol/types';
import { AccountType } from '@vegaprotocol/types';
import { headerClasses, wrapperClasses } from '../transfer-details';
import type { Transfer } from '../transfer-details';
import type { components } from '../../../../../../types/explorer';
type Transfer = components['schemas']['commandsv1Transfer'];
type AccountTypes = components['schemas']['vegaAccountType'];
const AccountType: Record<AccountTypes, string> = {
ACCOUNT_TYPE_UNSPECIFIED: 'Unspecified',
ACCOUNT_TYPE_INSURANCE: 'Insurance',
ACCOUNT_TYPE_SETTLEMENT: 'Settlement',
ACCOUNT_TYPE_MARGIN: 'Margin',
ACCOUNT_TYPE_GENERAL: 'General',
ACCOUNT_TYPE_FEES_INFRASTRUCTURE: 'Infrastructure',
ACCOUNT_TYPE_FEES_LIQUIDITY: 'Liquidity',
ACCOUNT_TYPE_FEES_MAKER: 'Maker',
ACCOUNT_TYPE_BOND: 'Bond',
ACCOUNT_TYPE_EXTERNAL: 'External',
ACCOUNT_TYPE_GLOBAL_INSURANCE: 'Global Insurance',
ACCOUNT_TYPE_GLOBAL_REWARD: 'Global Reward',
ACCOUNT_TYPE_PENDING_TRANSFERS: 'Pending Transfers',
ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: 'Maker Paid Fees',
ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: 'Maker Received Fees',
ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: 'LP Received Fees',
ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: 'Market Proposers',
ACCOUNT_TYPE_HOLDING: 'Holding',
};
interface TransferParticipantsProps {
transfer: Transfer;
@@ -30,22 +52,22 @@ export function TransferParticipants({
}: TransferParticipantsProps) {
// This mapping is required as the global account types require a type to be set, while
// the underlying protobufs allow for every field to be undefined.
const fromAcct =
const fromAcct: AccountTypes =
transfer.fromAccountType &&
transfer.fromAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
? AccountType[transfer.fromAccountType]
: AccountType.ACCOUNT_TYPE_GENERAL;
const fromAccountTypeLabel = transfer.fromAccountType
? AccountTypeMapping[fromAcct]
? transfer.fromAccountType
: 'ACCOUNT_TYPE_GENERAL';
const fromAccountTypeLabel: string = transfer.fromAccountType
? AccountType[fromAcct]
: 'Unknown';
const toAcct =
const toAcct: AccountTypes =
transfer.toAccountType &&
transfer.toAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
? AccountType[transfer.toAccountType]
: AccountType.ACCOUNT_TYPE_GENERAL;
? transfer.toAccountType
: 'ACCOUNT_TYPE_GENERAL';
const toAccountTypeLabel = transfer.fromAccountType
? AccountTypeMapping[toAcct]
? AccountType[toAcct]
: 'Unknown';
return (
@@ -27,9 +27,9 @@ export function TransferRepeat({ recurring }: TransferRepeatProps) {
<div className={wrapperClasses}>
<h2 className={headerClasses}>{t('Active epochs')}</h2>
<div className="relative block rounded-lg py-6 text-center p-6">
<p>
<div>
<EpochOverview id={recurring.startEpoch} />
</p>
</div>
<p className="leading-10 my-2">
<IconForEpoch
start={recurring.startEpoch}
@@ -37,13 +37,13 @@ export function TransferRepeat({ recurring }: TransferRepeatProps) {
current={data?.epoch.id}
/>
</p>
<p>
<div>
{recurring.endEpoch ? (
<EpochOverview id={recurring.endEpoch} />
) : (
<span>{t('Forever')}</span>
)}
</p>
</div>
</div>
</div>
);
@@ -8,7 +8,7 @@ import { DispatchMetricLabels } from '@vegaprotocol/types';
export type Metric = components['schemas']['vegaDispatchMetric'];
export type Strategy = components['schemas']['vegaDispatchStrategy'];
const metricLabels = {
const metricLabels: Record<Metric, string> = {
DISPATCH_METRIC_UNSPECIFIED: 'Unknown metric',
...DispatchMetricLabels,
};
@@ -3,7 +3,7 @@ import { TransferRepeat } from './blocks/transfer-repeat';
import { TransferRewards } from './blocks/transfer-rewards';
import { TransferParticipants } from './blocks/transfer-participants';
export type Recurring = components['schemas']['v1RecurringTransfer'];
export type Recurring = components['schemas']['commandsv1RecurringTransfer'];
export type Metric = components['schemas']['vegaDispatchMetric'];
export const wrapperClasses =
@@ -8,6 +8,7 @@ import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
import DeterministicOrderDetails from '../../order-details/deterministic-order-details';
import Hash from '../../links/hash';
import { TxOrderPeggedReferenceRow } from './order/tx-order-peg';
import { TxOrderIcebergDetails } from './order/tx-order-iceberg';
interface TxDetailsOrderProps {
txData: BlockExplorerTransactionResult | undefined;
@@ -32,6 +33,8 @@ export const TxDetailsOrder = ({
const marketId = txData.command.orderSubmission.marketId || '-';
const reference = txData.command.orderSubmission.peggedOrder;
const side = txData.command.orderSubmission.side;
const iceberg = txData.command.orderSubmission.icebergOpts;
const size = txData.command.orderSubmission.size;
let deterministicId = '';
@@ -74,6 +77,14 @@ export const TxDetailsOrder = ({
marketId={marketId}
/>
) : null}
{iceberg ? (
<TableRow modifier="bordered">
<TableCell>{t('Iceberg details')}</TableCell>
<TableCell>
<TxOrderIcebergDetails iceberg={iceberg} size={size} />
</TableCell>
</TableRow>
) : null}
</TableWithTbody>
{deterministicId.length > 0 ? (
@@ -10,7 +10,6 @@ import {
DropdownMenuTrigger,
DropdownMenuSubContent,
Icon,
Button,
} from '@vegaprotocol/ui-toolkit';
import type { Dispatch, SetStateAction } from 'react';
import { FilterLabel } from './tx-filter-label';
@@ -100,15 +99,13 @@ export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
<DropdownMenu
modal={false}
trigger={
<DropdownMenuTrigger className="ml-0">
<Button size="xs" data-testid="filter-trigger">
<FilterLabel filters={filters} />
</Button>
<DropdownMenuTrigger>
<FilterLabel filters={filters} />
</DropdownMenuTrigger>
}
>
<DropdownMenuContent>
{filters.size > 0 ? null : (
{filters.size > 1 ? null : (
<>
<DropdownMenuCheckboxItem
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
@@ -44,7 +44,7 @@ export const TxsListNavigation = ({
</Button>
<Button
size="xs"
disabled={!hasMoreTxs || loading}
disabled={!hasMoreTxs}
onClick={() => {
nextPage();
}}
@@ -16,7 +16,7 @@ interface StringMap {
const displayString: StringMap = {
OrderSubmission: 'Order Submission',
'Submit Order': 'Order',
OrderCancellation: 'Order Cancellation',
OrderCancellation: 'Cancel order',
OrderAmendment: 'Order Amendment',
VoteSubmission: 'Vote Submission',
WithdrawSubmission: 'Withdraw Submission',
@@ -44,8 +44,27 @@ const displayString: StringMap = {
ValidatorHeartbeat: 'Heartbeat',
'Validator Heartbeat': 'Heartbeat',
'Batch Market Instructions': 'Batch',
'Stop Orders Submission': 'Stop',
StopOrdersSubmission: 'Stop',
StopOrdersCancellation: 'Cancel stop',
'Stop Orders Cancellation': 'Cancel stop',
};
export function getLabelForOrderType(
orderType: string,
command: components['schemas']['v1InputData']
): string {
if (command.orderSubmission) {
if (command.orderSubmission.peggedOrder) {
return 'Peg';
}
if (command.orderSubmission.icebergOpts) {
return 'Iceberg';
}
}
return 'Order';
}
/**
* Given a proposal, will return a specific label
* @param chainEvent
@@ -117,6 +136,8 @@ export function getLabelForChainEvent(
return t('Signer threshold');
}
return t('Multisig update');
} else if (chainEvent.contractCall) {
return t('Contract call');
}
return t('Chain Event');
}
@@ -145,6 +166,7 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-250';
// This will get unwieldy and should probably produce a different colour of tag
// Note that colours are currently arbitrary
if (type === 'Chain Event' && !!command?.chainEvent) {
type = getLabelForChainEvent(command.chainEvent);
colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink';
@@ -156,6 +178,9 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
type = getLabelForProposal(command.proposalSubmission);
}
colours = 'text-black bg-vega-yellow';
} else if (type === 'Order' && command) {
type = getLabelForOrderType(orderType, command);
colours = 'text-white dark-text-white bg-vega-blue dark:bg-vega-blue';
}
if (type === 'Vote on Proposal') {
@@ -86,14 +86,18 @@ describe('Txs infinite list item', () => {
render(
<MockedProvider>
<MemoryRouter>
<TxsInfiniteListItem
type="testType"
submitter="testPubKey"
hash="testTxHash"
block="1"
code={0}
command={{}}
/>
<table>
<tbody>
<TxsInfiniteListItem
type="testType"
submitter="testPubKey"
hash="testTxHash"
block="1"
code={0}
command={{}}
/>
</tbody>
</table>
</MemoryRouter>
</MockedProvider>
);
@@ -14,9 +14,9 @@ const DEFAULT_TRUNCATE_LENGTH = 7;
export function getIdTruncateLength(screen: Screen): number {
if (['xxxl', 'xxl'].includes(screen)) {
return 64;
} else if (['xl', 'lg', 'md'].includes(screen)) {
return 32;
} else if (['xl', 'lg', 'md'].includes(screen)) {
return 16;
}
return DEFAULT_TRUNCATE_LENGTH;
}
@@ -5,11 +5,17 @@ import type { BlockExplorerTransactionResult } from '../../routes/types/block-ex
import { Side } from '@vegaprotocol/types';
import { MockedProvider } from '@apollo/client/testing';
const generateHash = (): string =>
Array.from(
{ length: 64 },
() => '0123456789ABCDEF'[Math.floor(Math.random() * 16)]
).join('');
const generateTxs = (number: number): BlockExplorerTransactionResult[] => {
return Array.from(Array(number)).map((_) => ({
block: '87901',
index: 2,
hash: '0F8B98DA0923A50786B852D9CA11E051CACC4C733E1DB93D535C7D81DBD10F6F',
hash: generateHash(),
submitter:
'4b782482f587d291e8614219eb9a5ee9280fa2c58982dee71d976782a9be1964',
type: 'Submit Order',
@@ -2,7 +2,7 @@ import { Table, TableRow } from '../table';
import { t } from '@vegaprotocol/i18n';
import { useFetch } from '@vegaprotocol/react-helpers';
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
import { getTxsDataUrl } from '../../hooks/use-txs-data';
import { getTxsDataUrl } from '../../hooks/get-txs-data-url';
import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit';
import EmptyList from '../empty-list/empty-list';
import { TxsInfiniteListItem } from './txs-infinite-list-item';
@@ -14,7 +14,7 @@ interface TxsPerBlockProps {
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
const filters = `filters[block.height]=${blockHeight}`;
const url = getTxsDataUrl({ limit: txCount.toString(), filters });
const url = getTxsDataUrl({ filters, count: txCount });
const {
state: { data, loading, error },
} = useFetch<BlockExplorerTransactions>(url);
-15
View File
@@ -5,8 +5,6 @@ const windowOrDefault = (key: string) => {
return (process.env[key] as string) || '';
};
const truthy = ['1', 'true'];
export const ENV = {
// Data sources
// Environment
@@ -20,19 +18,6 @@ export const ENV = {
governanceUrl: windowOrDefault('NX_VEGA_GOVERNANCE_URL'),
vegaRepoUrl: windowOrDefault('NX_VEGA_REPO_URL'),
},
flags: {
assets: truthy.includes(windowOrDefault('NX_EXPLORER_ASSETS')),
genesis: truthy.includes(windowOrDefault('NX_EXPLORER_GENESIS')),
governance: truthy.includes(windowOrDefault('NX_EXPLORER_GOVERNANCE')),
markets: truthy.includes(windowOrDefault('NX_EXPLORER_MARKETS')),
oracles: truthy.includes(windowOrDefault('NX_EXPLORER_ORACLES')),
txsList: truthy.includes(windowOrDefault('NX_EXPLORER_TXS_LIST')),
networkParameters: truthy.includes(
windowOrDefault('NX_EXPLORER_NETWORK_PARAMETERS')
),
parties: truthy.includes(windowOrDefault('NX_EXPLORER_PARTIES')),
validators: truthy.includes(windowOrDefault('NX_EXPLORER_VALIDATORS')),
},
addresses: {
feedback: windowOrDefault('NX_GITHUB_FEEDBACK_URL'),
},
-5
View File
@@ -1,5 +0,0 @@
import { ENV } from './env';
export default {
...ENV.flags,
};
@@ -0,0 +1,59 @@
import { DATA_SOURCES } from '../config';
type IGetTxsDataFirstPage = {
baseUrl?: string;
count?: number;
party?: string;
filters?: string;
};
interface IGetTxsDataPrevious extends IGetTxsDataFirstPage {
before: string;
}
interface IGetTxsDataNext extends IGetTxsDataFirstPage {
after: string;
}
type IGetTxsDataUrl =
| IGetTxsDataPrevious
| IGetTxsDataNext
| IGetTxsDataFirstPage;
export const BE_TXS_PER_REQUEST = 25;
/**
* Properly encodes the filters and parameters for a request to the block explorer
* API for transactions. As the API uses a slightly less common format for encoding
* filters, some of it is more manual than you might expect.
*
* @param params An object containing the pagination and filters
* @returns string URL to call
*/
export const getTxsDataUrl = (params: IGetTxsDataUrl) => {
const baseUrl =
params.baseUrl || `${DATA_SOURCES.blockExplorerUrl}/transactions`;
const url = new URL(baseUrl);
const count = `${params.count || BE_TXS_PER_REQUEST}`;
if ('before' in params && params.before?.length > 0) {
url.searchParams.append('last', count);
url.searchParams.append('before', params.before);
} else if ('after' in params && params.after?.length > 0) {
url.searchParams.append('first', count);
url.searchParams.append('after', params.after);
} else {
url.searchParams.append('first', count);
}
// Hacky fix for param as array
let urlAsString = url.toString();
if (params.filters && params.filters?.length > 0) {
urlAsString += '&' + params.filters.replaceAll(' ', '%20');
}
if (params.party && params.party?.length > 0) {
urlAsString += `&filters[tx.submitter]=${params.party}`;
}
return urlAsString;
};
@@ -0,0 +1,48 @@
import { getTxsDataUrl } from './get-txs-data-url'; // import the function to be tested
describe('getTxsDataUrl', () => {
it('should return the correct URL without filters and party', () => {
const params = {
count: 10,
baseUrl: 'https://example.com/transactions',
};
const expectedUrl = 'https://example.com/transactions?first=10';
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
});
it('should return the correct URL with "before" in params', () => {
const params = {
count: 5,
before: '100.1',
baseUrl: 'https://example.com/transactions',
};
const expectedUrl = 'https://example.com/transactions?last=5&before=100.1';
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
});
it('should return the correct URL with "after" in params', () => {
const params = {
count: 5,
after: '222.1',
baseUrl: 'https://example.com/transactions',
};
const expectedUrl = 'https://example.com/transactions?first=5&after=222.1';
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
});
it('should return the correct URL with filters and party', () => {
const params = {
count: 10,
filters: 'filters[cmd.type]=Made Up Transaction',
party: '1234',
baseUrl: 'https://example.com/transactions',
};
const expectedUrl =
'https://example.com/transactions?first=10&filters[cmd.type]=Made%20Up%20Transaction&filters[tx.submitter]=1234';
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
});
});
+103 -92
View File
@@ -1,130 +1,141 @@
import { useCallback, useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import type { URLSearchParamsInit } from 'react-router-dom';
import { useCallback } from 'react';
import { useFetch } from '@vegaprotocol/react-helpers';
import type {
BlockExplorerTransactionResult,
BlockExplorerTransactions,
} from '../routes/types/block-explorer-response';
import { DATA_SOURCES } from '../config';
import isNumber from 'lodash/isNumber';
import { AllFilterOptions } from '../components/txs/tx-filter';
import type { FilterOption } from '../components/txs/tx-filter';
import { BE_TXS_PER_REQUEST, getTxsDataUrl } from './get-txs-data-url';
export interface TxsStateProps {
txsData: BlockExplorerTransactionResult[];
hasMoreTxs: boolean;
cursor: string;
previousCursors: string[];
hasPreviousPage: boolean;
export function getTypeFilters(filters?: Set<FilterOption>) {
if (!filters) {
return '';
} else if (filters.size > 1) {
return '';
}
const forcedSingleFilter = Array.from(filters)[0];
return `filters[cmd.type]=${forcedSingleFilter}`;
}
export interface IUseTxsData {
limit: number;
filters?: string;
count?: number;
before?: string;
after?: string;
party?: string;
filters?: Set<FilterOption>;
}
interface IGetTxsDataUrl {
limit: string;
filters?: string;
}
export const useTxsData = ({
count = 25,
before,
after,
filters,
party,
}: IUseTxsData) => {
const [, setSearchParams] = useSearchParams();
let hasMoreTxs = true;
let txsData: BlockExplorerTransactionResult[] = [];
export const getTxsDataUrl = ({ limit, filters }: IGetTxsDataUrl) => {
const url = new URL(`${DATA_SOURCES.blockExplorerUrl}/transactions`);
if (limit) {
url.searchParams.append('limit', limit);
}
// Hacky fix for param as array
let urlAsString = url.toString();
if (filters) {
urlAsString += '&' + filters.replace(' ', '%20');
}
return urlAsString;
};
export const useTxsData = ({ limit, filters }: IUseTxsData) => {
const [
{ txsData, hasMoreTxs, cursor, previousCursors, hasPreviousPage },
setTxsState,
] = useState<TxsStateProps>({
txsData: [],
hasMoreTxs: false,
previousCursors: [],
cursor: '',
hasPreviousPage: false,
const url = getTxsDataUrl({
filters: getTypeFilters(filters),
count,
before,
after,
party,
});
const url = getTxsDataUrl({ limit: limit.toString(), filters });
const {
state: { data, error, loading },
refetch,
} = useFetch<BlockExplorerTransactions>(url, {}, true);
useEffect(() => {
if (!loading && data && isNumber(data.transactions.length)) {
setTxsState((prev) => {
return {
...prev,
txsData: data.transactions,
hasMoreTxs: data.transactions.length >= limit,
cursor: data?.transactions.at(-1)?.cursor || '',
};
});
}
}, [loading, setTxsState, data, limit]);
if (!loading && data && isNumber(data.transactions.length)) {
hasMoreTxs = data.transactions.length >= count;
txsData = data.transactions;
}
const nextPage = useCallback(() => {
const c = data?.transactions.at(0)?.cursor;
const newPreviousCursors = c ? [...previousCursors, c] : previousCursors;
setTxsState((prev) => ({
...prev,
hasPreviousPage: true,
previousCursors: newPreviousCursors,
}));
return refetch({
limit,
before: cursor,
});
}, [data, previousCursors, cursor, limit, refetch]);
const after = data?.transactions.at(-1)?.cursor || '';
const params: URLSearchParamsInit = { after };
if (filters) {
params.filters = Array.from(filters).join(',');
}
setSearchParams(params);
}, [filters, data, setSearchParams]);
const previousPage = useCallback(() => {
const previousCursor = [...previousCursors].pop();
const newPreviousCursors = previousCursors.slice(0, -1);
setTxsState((prev) => ({
...prev,
hasPreviousPage: newPreviousCursors.length > 0,
previousCursors: newPreviousCursors,
}));
return refetch({
limit,
before: previousCursor,
});
}, [previousCursors, limit, refetch]);
const before = data?.transactions[0]?.cursor || '';
const params: URLSearchParamsInit = { before };
if (filters && filters.size > 0 && filters.size === 1) {
params.filters = Array.from(filters)[0];
}
setSearchParams(params);
}, [filters, data, setSearchParams]);
const refreshTxs = useCallback(async () => {
setTxsState(() => ({
txsData: [],
cursor: '',
previousCursors: [],
hasMoreTxs: false,
hasPreviousPage: false,
}));
const params: URLSearchParamsInit = {};
if (filters && filters.size > 0 && filters.size === 1) {
params.filters = Array.from(filters)[0];
}
setSearchParams(params);
refetch({ limit });
}, [setTxsState, limit, refetch, filters]); // eslint-disable-line react-hooks/exhaustive-deps
refetch({ count: BE_TXS_PER_REQUEST });
}, [setSearchParams, refetch, filters]);
const updateFilters = useCallback(
(newFilters: Set<FilterOption>) => {
const params: URLSearchParamsInit = {};
if (newFilters && newFilters.size === 1) {
params.filters = Array.from(newFilters)[0];
}
setSearchParams(params);
},
[setSearchParams]
);
return {
updateFilters,
txsData,
loading,
error,
hasMoreTxs,
hasPreviousPage,
previousCursors,
cursor,
refreshTxs,
nextPage,
previousPage,
};
};
/**
* Returns a Set of filters based on the URLSearchParams, or
* defaults to all.
* @param params
* @returns Set
*/
export function getInitialFilters(params: URLSearchParams): Set<FilterOption> {
const defaultFilters = new Set(AllFilterOptions);
const p = params.get('filters');
if (!p) {
return defaultFilters;
}
const filters = new Set<FilterOption>();
p.split(',').forEach((f) => {
if (AllFilterOptions.includes(f as FilterOption)) {
filters.add(f as FilterOption);
}
});
if (filters.size === 0) {
return defaultFilters;
}
return filters;
}
@@ -204,6 +204,7 @@ describe('Block', () => {
(useFetch as jest.Mock).mockReturnValue({
state: { data: createBlockResponse(1), loading: false, error: null },
});
render(renderComponent(1));
await waitFor(() => screen.getByTestId('block-header'));
expect(screen.getByTestId('previous-block-button')).toHaveAttribute(
@@ -1,7 +1,5 @@
import { Link, useParams } from 'react-router-dom';
import { DATA_SOURCES } from '../../../config';
import { getDateTimeFormat } from '@vegaprotocol/utils';
import type { TendermintBlocksResponse } from '../tendermint-blocks-response';
import { RouteTitle } from '../../../components/route-title';
import { TimeAgo } from '../../../components/time-ago';
import {
@@ -14,7 +12,7 @@ import { TxsPerBlock } from '../../../components/txs/txs-per-block';
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
import { Routes } from '../../route-names';
import { t } from '@vegaprotocol/i18n';
import { useFetch } from '@vegaprotocol/react-helpers';
import { useBlockInfo } from '@vegaprotocol/tendermint';
import { NodeLink } from '../../../components/links';
import { useDocumentTitle } from '../../../hooks/use-document-title';
import EmptyList from '../../../components/empty-list/empty-list';
@@ -24,10 +22,7 @@ const Block = () => {
useDocumentTitle(['Blocks', `Block #${block}`]);
const {
state: { data: blockData, loading, error },
} = useFetch<TendermintBlocksResponse>(
`${DATA_SOURCES.tendermintUrl}/block?height=${block}`,
{ cache: 'force-cache' }
);
} = useBlockInfo(Number(block));
return (
<section>
@@ -54,7 +54,7 @@ export const PartyBlockStake = ({
{p?.stakingSummary.currentStakeAvailable ? (
<KeyValueTable>
<KeyValueTableRow noBorder={true}>
<div>{t('Available stake')}</div>
<div>{t('Associated to key')}</div>
<div>
<GovernanceAssetBalance
price={p.stakingSummary.currentStakeAvailable}
@@ -62,7 +62,7 @@ export const PartyBlockStake = ({
</div>
</KeyValueTableRow>
<KeyValueTableRow noBorder={true}>
<div>{t('Active stake')}</div>
<div>{t('Staked to validator')}</div>
<div>
<GovernanceAssetBalance price={linkedStake || '0'} />
</div>
@@ -15,9 +15,13 @@ import { PartyBlockAccounts } from './components/party-block-accounts';
import { isValidPartyId } from './components/party-id-error';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
import type { FilterOption } from '../../../components/txs/tx-filter';
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
import { useSearchParams } from 'react-router-dom';
const Party = () => {
const [params] = useSearchParams();
const [filters, setFilters] = useState(new Set(AllFilterOptions));
const { party } = useParams<{ party: string }>();
@@ -27,24 +31,21 @@ const Party = () => {
const partyId = toNonHex(party ? party : '');
const { isMobile } = useScreenDimensions();
const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]);
const baseFilters = `filters[tx.submitter]=${partyId}`;
const f =
filters && filters.size === 1
? `${baseFilters}&filters[cmd.type]=${Array.from(filters)[0]}`
: baseFilters;
const {
hasMoreTxs,
nextPage,
refreshTxs,
previousPage,
error,
refreshTxs,
loading,
txsData,
hasPreviousPage,
hasMoreTxs,
updateFilters,
} = useTxsData({
limit: 25,
filters: f,
filters: filters.size === 1 ? filters : undefined,
before: params.get('before') || undefined,
after: !params.get('before') ? params.get('after') || undefined : undefined,
party: partyId,
});
const variables = useMemo(() => ({ partyId }), [partyId]);
@@ -67,7 +68,7 @@ const Party = () => {
text: t('Go back'),
action: () => navigate(-1),
className: 'py-1',
size: 'sm',
size: 'small',
}}
/>
</div>
@@ -102,15 +103,21 @@ const Party = () => {
refreshTxs={refreshTxs}
nextPage={nextPage}
previousPage={previousPage}
hasPreviousPage={hasPreviousPage}
hasPreviousPage={true}
loading={loading}
hasMoreTxs={hasMoreTxs}
>
<TxsFilter filters={filters} setFilters={setFilters} />
<TxsFilter
filters={filters}
setFilters={(f) => {
setFilters(f);
updateFilters(f as Set<FilterOption>);
}}
/>
</TxsListNavigation>
{!error && txsData ? (
<TxsInfiniteList
hasMoreTxs={hasMoreTxs}
hasMoreTxs={true}
areTxsLoading={loading}
txs={txsData}
loadMoreTxs={nextPage}
@@ -14,7 +14,6 @@ import { Block } from './blocks/id';
import { Blocks } from './blocks/home';
import { Tx } from './txs/id';
import { TxsList } from './txs/home';
import flags from '../config/flags';
import { t } from '@vegaprotocol/i18n';
import { Routes } from './route-names';
import { NetworkParameters } from './network-parameters';
@@ -30,6 +29,7 @@ import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
import { remove0x } from '@vegaprotocol/utils';
import { PartyAccountsByAsset } from './parties/id/accounts';
import { Disclaimer } from './pages/disclaimer';
import { FLAGS } from '@vegaprotocol/environment';
export type Navigable = {
path: string;
@@ -59,7 +59,7 @@ type Route = RouteItem & {
children?: RouteItem[];
};
const partiesRoutes: Route[] = flags.parties
const partiesRoutes: Route[] = FLAGS.EXPLORER_PARTIES
? [
{
path: Routes.PARTIES,
@@ -119,7 +119,7 @@ const partiesRoutes: Route[] = flags.parties
]
: [];
const assetsRoutes: Route[] = flags.assets
const assetsRoutes: Route[] = FLAGS.EXPLORER_ASSETS
? [
{
path: Routes.ASSETS,
@@ -147,7 +147,7 @@ const assetsRoutes: Route[] = flags.assets
]
: [];
const genesisRoutes: Route[] = flags.genesis
const genesisRoutes: Route[] = FLAGS.EXPLORER_GENESIS
? [
{
path: Routes.GENESIS,
@@ -163,7 +163,7 @@ const genesisRoutes: Route[] = flags.genesis
]
: [];
const governanceRoutes: Route[] = flags.governance
const governanceRoutes: Route[] = FLAGS.EXPLORER_GOVERNANCE
? [
{
path: Routes.GOVERNANCE,
@@ -179,7 +179,7 @@ const governanceRoutes: Route[] = flags.governance
]
: [];
const marketsRoutes: Route[] = flags.markets
const marketsRoutes: Route[] = FLAGS.EXPLORER_MARKETS
? [
{
path: Routes.MARKETS,
@@ -207,7 +207,7 @@ const marketsRoutes: Route[] = flags.markets
]
: [];
const networkParametersRoutes: Route[] = flags.networkParameters
const networkParametersRoutes: Route[] = FLAGS.EXPLORER_NETWORK_PARAMETERS
? [
{
path: Routes.NETWORK_PARAMETERS,
@@ -225,7 +225,7 @@ const networkParametersRoutes: Route[] = flags.networkParameters
]
: [];
const validators: Route[] = flags.validators
const validators: Route[] = FLAGS.EXPLORER_VALIDATORS
? [
{
path: Routes.VALIDATORS,
+19 -16
View File
@@ -1,14 +1,14 @@
import { t } from '@vegaprotocol/i18n';
import { RouteTitle } from '../../../components/route-title';
import { TxsInfiniteList } from '../../../components/txs';
import { useTxsData } from '../../../hooks/use-txs-data';
import { useTxsData, getInitialFilters } from '../../../hooks/use-txs-data';
import { useDocumentTitle } from '../../../hooks/use-document-title';
import { useState } from 'react';
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
import { TxsFilter } from '../../../components/txs/tx-filter';
import type { FilterOption } from '../../../components/txs/tx-filter';
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
const BE_TXS_PER_REQUEST = 25;
import { useSearchParams } from 'react-router-dom';
export const TxsList = () => {
useDocumentTitle(['Transactions']);
@@ -27,25 +27,22 @@ export const TxsList = () => {
* @returns {JSX.Element} Transaction List and controls
*/
export const TxsListFiltered = () => {
const [filters, setFilters] = useState(new Set(AllFilterOptions));
const f =
filters && filters.size === 1
? `filters[cmd.type]=${Array.from(filters)[0]}`
: '';
const [params] = useSearchParams();
const [filters, setFilters] = useState(getInitialFilters(params));
const {
hasMoreTxs,
nextPage,
previousPage,
error,
refreshTxs,
loading,
txsData,
hasPreviousPage,
hasMoreTxs,
updateFilters,
} = useTxsData({
limit: BE_TXS_PER_REQUEST,
filters: f,
filters: filters.size === 1 ? filters : undefined,
before: params.get('before') || undefined,
after: !params.get('before') ? params.get('after') || undefined : undefined,
});
return (
@@ -54,11 +51,17 @@ export const TxsListFiltered = () => {
refreshTxs={refreshTxs}
nextPage={nextPage}
previousPage={previousPage}
hasPreviousPage={hasPreviousPage}
hasPreviousPage={true}
loading={loading}
hasMoreTxs={hasMoreTxs}
>
<TxsFilter filters={filters} setFilters={setFilters} />
<TxsFilter
filters={filters}
setFilters={(f) => {
setFilters(f);
updateFilters(f as Set<FilterOption>);
}}
/>
</TxsListNavigation>
<TxsInfiniteList
hasFilters={filters.size > 0}
@@ -15,6 +15,9 @@ query ExplorerNodes {
stakedByDelegates
stakedTotal
pendingStake
rankingScore {
performanceScore
}
epochData {
total
offline
@@ -6,7 +6,7 @@ const defaultOptions = {} as const;
export type ExplorerNodesQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type ExplorerNodesQuery = { __typename?: 'Query', nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, infoUrl: string, avatarUrl?: string | null, pubkey: string, tmPubkey: string, ethereumAddress: string, location: string, status: Types.NodeStatus, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null } } | null> | null } };
export type ExplorerNodesQuery = { __typename?: 'Query', nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, infoUrl: string, avatarUrl?: string | null, pubkey: string, tmPubkey: string, ethereumAddress: string, location: string, status: Types.NodeStatus, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, rankingScore: { __typename?: 'RankingScore', performanceScore: string }, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null } } | null> | null } };
export const ExplorerNodesDocument = gql`
@@ -27,6 +27,9 @@ export const ExplorerNodesDocument = gql`
stakedByDelegates
stakedTotal
pendingStake
rankingScore {
performanceScore
}
epochData {
total
offline
@@ -91,7 +91,15 @@ export const ValidatorsPage = () => {
const { data: tmData } = useTendermintValidators(5000);
const { data, loading, error, refetch } = useExplorerNodesQuery();
const validators = compact(data?.nodesConnection.edges?.map((e) => e?.node));
const validators = compact(
data?.nodesConnection.edges
?.map((e) => e?.node)
.filter(
(node) =>
node?.rankingScore?.performanceScore &&
new BigNumber(node.rankingScore.performanceScore).isGreaterThan(0)
)
);
// voting power
const powers = compact(tmData?.result.validators).map(
+398 -72
View File
@@ -3,7 +3,7 @@
* Do not make direct changes to the file.
*/
/** Type helpers */
/** OneOf type helpers */
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = T | U extends object
? (Without<T, U> & U) | (Without<U, T> & T)
@@ -41,6 +41,8 @@ export interface paths {
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: {
/**
@@ -101,6 +103,17 @@ export interface components {
| 'TIME_IN_FORCE_FOK'
| 'TIME_IN_FORCE_GFA'
| 'TIME_IN_FORCE_GFN';
/**
* @description - EXPIRY_STRATEGY_UNSPECIFIED: Never valid
* - EXPIRY_STRATEGY_CANCELS: Stop order should be cancelled if the expiry time is reached.
* - EXPIRY_STRATEGY_SUBMIT: Order should be submitted if the expiry time is reached.
* @default EXPIRY_STRATEGY_UNSPECIFIED
* @enum {string}
*/
readonly StopOrderExpiryStrategy:
| 'EXPIRY_STRATEGY_UNSPECIFIED'
| 'EXPIRY_STRATEGY_CANCELS'
| 'EXPIRY_STRATEGY_SUBMIT';
/**
* @default METHOD_UNSPECIFIED
* @enum {string}
@@ -143,6 +156,36 @@ export interface components {
/** Type of transaction */
readonly type?: string;
};
/** Request for cancelling a recurring transfer */
readonly commandsv1CancelTransfer: {
/** @description Transfer ID of the transfer to cancel. */
readonly transferId?: string;
};
/** Specific details for a one off transfer */
readonly commandsv1OneOffTransfer: {
/**
* Format: int64
* @description Timestamp in Unix nanoseconds for when the transfer should be delivered into the receiver's account.
*/
readonly deliverOn?: string;
};
/** Specific details for a recurring transfer */
readonly commandsv1RecurringTransfer: {
/** @description Optional parameter defining how a transfer is dispatched. */
readonly dispatchStrategy?: components['schemas']['vegaDispatchStrategy'];
/**
* Format: uint64
* @description Last epoch at which this transfer shall be paid.
*/
readonly endEpoch?: string;
/** @description Factor needs to be > 0. */
readonly factor?: string;
/**
* Format: uint64
* @description First epoch from which this transfer shall be paid.
*/
readonly startEpoch?: string;
};
/** Transfer initiated by a party */
readonly commandsv1Transfer: {
/** @description Amount to be taken from the source account. This field is an unsigned integer scaled to the asset's decimal places. */
@@ -154,8 +197,8 @@ export interface components {
* should be taken.
*/
readonly fromAccountType?: components['schemas']['vegaAccountType'];
readonly oneOff?: components['schemas']['v1OneOffTransfer'];
readonly recurring?: components['schemas']['v1RecurringTransfer'];
readonly oneOff?: components['schemas']['commandsv1OneOffTransfer'];
readonly recurring?: components['schemas']['commandsv1RecurringTransfer'];
/** @description Reference to be attached to the transfer. */
readonly reference?: string;
/** @description Public key of the destination account. */
@@ -171,8 +214,19 @@ export interface components {
};
readonly protobufAny: {
readonly '@type'?: string;
[key: string]: unknown | undefined;
[key: string]: unknown;
};
/**
* @description `NullValue` is a singleton enumeration to represent the null value for the
* `Value` type union.
*
* The JSON representation for `NullValue` is JSON `null`.
*
* - NULL_VALUE: Null value.
* @default NULL_VALUE
* @enum {string}
*/
readonly protobufNullValue: 'NULL_VALUE';
/** Used to announce a node as a new pending validator */
readonly v1AnnounceNode: {
/** @description AvatarURL of the validator. */
@@ -225,18 +279,19 @@ export interface components {
readonly amendments?: readonly components['schemas']['v1OrderAmendment'][];
/** @description List of order cancellations to be processed sequentially. */
readonly cancellations?: readonly components['schemas']['v1OrderCancellation'][];
/** @description List of stop order cancellations to be processed sequentially. */
readonly stopOrdersCancellation?: readonly components['schemas']['v1StopOrdersCancellation'][];
/** @description List of stop order submissions to be processed sequentially. */
readonly stopOrdersSubmission?: readonly components['schemas']['v1StopOrdersSubmission'][];
/** @description List of order submissions to be processed sequentially. */
readonly submissions?: readonly components['schemas']['v1OrderSubmission'][];
};
/** Request for cancelling a recurring transfer */
readonly v1CancelTransfer: {
/** @description Transfer ID of the transfer to cancel. */
readonly transferId?: string;
};
/** Event forwarded to the Vega network to provide information on events happening on other networks */
readonly v1ChainEvent: {
/** @description Built-in asset event. */
readonly builtin?: components['schemas']['vegaBuiltinAssetEvent'];
/** Arbitrary contract call */
readonly contractCall?: components['schemas']['vegaEthContractCallEvent'];
/** @description Ethereum ERC20 event. */
readonly erc20?: components['schemas']['vegaERC20Event'];
/** @description Ethereum ERC20 multisig event. */
@@ -301,6 +356,19 @@ export interface components {
/** Transaction corresponding to the hash */
readonly transaction?: components['schemas']['blockexplorerapiv1Transaction'];
};
/** Iceberg order options */
readonly v1IcebergOpts: {
/**
* Format: uint64
* @description Minimum allowed remaining size of the order before it is replenished back to its peak size.
*/
readonly minimumVisibleSize?: string;
/**
* Format: uint64
* @description Size of the order that is made visible and can be traded with during the execution of a single order.
*/
readonly peakSize?: string;
};
readonly v1InfoResponse: {
/** Commit hash from which the data node was built */
readonly commitHash?: string;
@@ -325,7 +393,7 @@ export interface components {
*/
readonly blockHeight?: string;
/** @description Command to request cancelling a recurring transfer. */
readonly cancelTransfer?: components['schemas']['v1CancelTransfer'];
readonly cancelTransfer?: components['schemas']['commandsv1CancelTransfer'];
/**
* @description Command used by a validator to submit an event forwarded to the Vega network to provide information
* on events happening on other networks, to be used by a foreign chain
@@ -381,6 +449,10 @@ export interface components {
readonly protocolUpgradeProposal?: components['schemas']['v1ProtocolUpgradeProposal'];
/** @description Command used by a validator to submit a floating point value. */
readonly stateVariableProposal?: components['schemas']['v1StateVariableProposal'];
/** @description Command to cancel stop orders. */
readonly stopOrdersCancellation?: components['schemas']['v1StopOrdersCancellation'];
/** @description Command to submit a pair of stop orders. */
readonly stopOrdersSubmission?: components['schemas']['v1StopOrdersSubmission'];
/** @description Command to submit a transfer. */
readonly transfer?: components['schemas']['commandsv1Transfer'];
/** @description Command to remove tokens delegated to a validator. */
@@ -448,9 +520,9 @@ export interface components {
readonly commitmentAmount?: string;
/** @description Nominated liquidity fee factor, which is an input to the calculation of taker fees on the market, as per setting fees and rewarding liquidity providers. */
readonly fee?: string;
/** @description Market ID for the order, required field. */
/** @description Market ID for the order. */
readonly marketId?: string;
/** @description Reference to be added to every order created out of this liquidityProvisionSubmission. */
/** @description Reference to be added to every order created out of this liquidity provision submission. */
readonly reference?: string;
/** @description Set of liquidity sell orders to meet the liquidity provision obligation. */
readonly sells?: readonly components['schemas']['vegaLiquidityOrder'][];
@@ -530,15 +602,6 @@ export interface components {
| 'TYPE_STAKE_TOTAL_SUPPLY'
| 'TYPE_SIGNER_THRESHOLD_SET'
| 'TYPE_GOVERNANCE_VALIDATE_ASSET';
/** Specific details for a one off transfer */
readonly v1OneOffTransfer: {
/**
* Format: int64
* @description Unix timestamp in nanoseconds. Time at which the
* transfer should be delivered into the To account.
*/
readonly deliverOn?: string;
};
/** Command to submit new Oracle data from third party providers */
readonly v1OracleDataSubmission: {
/**
@@ -596,10 +659,12 @@ export interface components {
readonly v1OrderSubmission: {
/**
* Format: int64
* @description Timestamp for when the order will expire, in nanoseconds,
* @description Timestamp in Unix nanoseconds for when the order will expire,
* required field only for `Order.TimeInForce`.TIME_IN_FORCE_GTT`.
*/
readonly expiresAt?: string;
/** @description Parameters used to specify an iceberg order. */
readonly icebergOpts?: components['schemas']['v1IcebergOpts'];
/** @description Market ID for the order, required field. */
readonly marketId?: string;
/** @description Used to specify the details for a pegged order. */
@@ -699,23 +764,6 @@ export interface components {
readonly v1PubKey: {
readonly key?: string;
};
/** Specific details for a recurring transfer */
readonly v1RecurringTransfer: {
/** @description Optional parameter defining how a transfer is dispatched. */
readonly dispatchStrategy?: components['schemas']['vegaDispatchStrategy'];
/**
* Format: uint64
* @description Last epoch at which this transfer shall be paid.
*/
readonly endEpoch?: string;
/** @description Factor needs to be > 0. */
readonly factor?: string;
/**
* Format: uint64
* @description First epoch from which this transfer shall be paid.
*/
readonly startEpoch?: string;
};
/**
* @description Signature to authenticate a transaction and to be verified by the Vega
* network.
@@ -732,7 +780,7 @@ export interface components {
readonly version?: number;
};
readonly v1Signer: {
/** In case of an open oracle - Ethereum address will be submitted */
/** @description In case of an open oracle - Ethereum address will be submitted. */
readonly ethAddress?: components['schemas']['v1ETHAddress'];
/**
* @description List of authorized public keys that signed the data for this
@@ -746,6 +794,55 @@ export interface components {
/** @description State value proposal details. */
readonly proposal?: components['schemas']['vegaStateValueProposal'];
};
/** Price and expiry configuration for a stop order */
readonly v1StopOrderSetup: {
/**
* Format: int64
* @description Optional expiry timestamp.
*/
readonly expiresAt?: string;
/** @description Strategy to adopt if the expiry time is reached. */
readonly expiryStrategy?: components['schemas']['StopOrderExpiryStrategy'];
/** @description Order to be submitted once the trigger is breached. */
readonly orderSubmission?: components['schemas']['v1OrderSubmission'];
/** @description Fixed price at which the order will be submitted. */
readonly price?: string;
/** @description Trailing percentage at which the order will be submitted. */
readonly trailingPercentOffset?: string;
};
/**
* Cancel a stop order.
* The following combinations are available:
* Empty object will cancel all stop orders for the party
* Market ID alone will cancel all stop orders in a market
* Market ID and order ID will cancel a specific stop order in a market
* If the stop order is part of an OCO, both stop orders will be cancelled
*/
readonly v1StopOrdersCancellation: {
/** @description Optional market ID. */
readonly marketId?: string;
/** @description Optional order ID. */
readonly stopOrderId?: string;
};
/**
* Stop order submission submits stops orders.
* It is possible to make a single stop order submission by
* specifying a single direction,
* or an OCO (One Cancels the Other) stop order submission
* by specifying a configuration for both directions
*/
readonly v1StopOrdersSubmission: {
/**
* @description Stop order that will be triggered
* if the price falls below a given trigger price.
*/
readonly fallsBelow?: components['schemas']['v1StopOrderSetup'];
/**
* @description Stop order that will be triggered
* if the price rises above a given trigger price.
*/
readonly risesAbove?: components['schemas']['v1StopOrderSetup'];
};
readonly v1UndelegateSubmission: {
/**
* @description Optional, if not specified = ALL.
@@ -822,6 +919,7 @@ export interface components {
* - ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: Per asset reward account for fees received by makers
* - ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: Per asset reward account for fees received by liquidity providers
* - ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: Per asset reward account for market proposers when the market goes above some trading threshold
* - ACCOUNT_TYPE_HOLDING: Per asset account for holding in-flight unfilled orders' funds
* @default ACCOUNT_TYPE_UNSPECIFIED
* @enum {string}
*/
@@ -842,7 +940,8 @@ export interface components {
| 'ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES'
| 'ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES'
| 'ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES'
| 'ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS';
| 'ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS'
| 'ACCOUNT_TYPE_HOLDING';
/** Vega representation of an external asset */
readonly vegaAssetDetails: {
/** @description Vega built-in asset. */
@@ -898,6 +997,14 @@ export interface components {
/** @description Vega network internal asset ID. */
readonly vegaAssetId?: string;
};
readonly vegaCancelTransfer: {
/** Configuration for cancellation of a governance-initiated transfer */
readonly changes?: components['schemas']['vegaCancelTransferConfiguration'];
};
readonly vegaCancelTransferConfiguration: {
/** @description ID of the governance transfer proposal. */
readonly transferId?: string;
};
/**
* @description DataSourceDefinition represents the top level object that deals with data sources.
* DataSourceDefinition can be external or internal, with whatever number of data sources are defined
@@ -912,6 +1019,7 @@ export interface components {
* It contains one of any of the defined `SourceType` variants.
*/
readonly vegaDataSourceDefinitionExternal: {
readonly ethCall?: components['schemas']['vegaEthCallSpec'];
readonly oracle?: components['schemas']['vegaDataSourceSpecConfiguration'];
};
/**
@@ -1147,6 +1255,64 @@ export interface components {
/** @description Address into which the bridge will release the funds. */
readonly receiverAddress?: string;
};
/** @description Specifies a data source that derives its content from calling a read method on an Ethereum contract. */
readonly vegaEthCallSpec: {
/** @description The ABI of that contract. */
readonly abi?: readonly Record<string, never>[];
/** @description Ethereum address of the contract to call. */
readonly address?: string;
/**
* @description List of arguments to pass to method call.
* Protobuf 'Value' wraps an arbitrary JSON type that is mapped to an Ethereum type according to the ABI.
*/
readonly args?: readonly Record<string, never>[];
/** @description Name of the method on the contract to call. */
readonly method?: string;
/** @description Conditions for determining when to call the contract method. */
readonly trigger?: components['schemas']['vegaEthCallTrigger'];
};
/** @description Determines when the contract method should be called. */
readonly vegaEthCallTrigger: {
readonly timeTrigger?: components['schemas']['vegaEthTimeTrigger'];
};
/** Result of calling an arbitrary Ethereum contract method */
readonly vegaEthContractCallEvent: {
/**
* Format: uint64
* @description Ethereum block height.
*/
readonly blockHeight?: string;
/**
* Format: uint64
* @description Ethereum block time in Unix seconds.
*/
readonly blockTime?: string;
/**
* Format: byte
* @description Result of contract call, packed according to the ABI stored in the associated data source spec.
*/
readonly result?: string;
/** @description ID of the data source spec that triggered this contract call. */
readonly specId?: string;
};
/** @description Trigger for an Ethereum call based on the Ethereum block timestamp. Can be one-off or repeating. */
readonly vegaEthTimeTrigger: {
/**
* Format: uint64
* @description Repeat the call every n seconds after the inital call. If no time for initial call was specified, begin repeating immediately.
*/
readonly every?: string;
/**
* Format: uint64
* @description Trigger when the Ethereum time is greater or equal to this time, in Unix seconds.
*/
readonly initial?: string;
/**
* Format: uint64
* @description If repeating, stop once Ethereum time is greater than this time, in Unix seconds. If not set, then repeat indefinitely.
*/
readonly until?: string;
};
/** Future product configuration */
readonly vegaFutureProduct: {
/** @description Binding between the data source spec and the settlement data. */
@@ -1160,6 +1326,14 @@ export interface components {
/** @description Asset ID for the product's settlement asset. */
readonly settlementAsset?: string;
};
/**
* @default GOVERNANCE_TRANSFER_TYPE_UNSPECIFIED
* @enum {string}
*/
readonly vegaGovernanceTransferType:
| 'GOVERNANCE_TRANSFER_TYPE_UNSPECIFIED'
| 'GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING'
| 'GOVERNANCE_TRANSFER_TYPE_BEST_EFFORT';
/** Instrument configuration */
readonly vegaInstrumentConfiguration: {
/** @description Instrument code, human-readable shortcode used to describe the instrument. */
@@ -1168,6 +1342,8 @@ export interface components {
readonly future?: components['schemas']['vegaFutureProduct'];
/** @description Instrument name. */
readonly name?: string;
/** @description Spot. */
readonly spot?: components['schemas']['vegaSpotProduct'];
};
readonly vegaKeyValueBundle: {
readonly key?: string;
@@ -1258,14 +1434,14 @@ export interface components {
/** @description Configuration of the new market. */
readonly changes?: components['schemas']['vegaNewMarketConfiguration'];
};
/** Configuration for a new market on Vega */
/** Configuration for a new futures market on Vega */
readonly vegaNewMarketConfiguration: {
/**
* Format: uint64
* @description Decimal places used for the new market, sets the smallest price increment on the book.
* @description Decimal places used for the new futures market, sets the smallest price increment on the book.
*/
readonly decimalPlaces?: string;
/** @description New market instrument configuration. */
/** @description New futures market instrument configuration. */
readonly instrument?: components['schemas']['vegaInstrumentConfiguration'];
/** @description Linear slippage factor is used to cap the slippage component of maintenance margin - it is applied to the slippage volume. */
readonly linearSlippageFactor?: string;
@@ -1278,11 +1454,11 @@ export interface components {
* price levels over which automated liquidity provision orders will be deployed.
*/
readonly lpPriceRange?: string;
/** @description Optional new market metadata, tags. */
/** @description Optional new futures market metadata, tags. */
readonly metadata?: readonly string[];
/**
* Format: int64
* @description Decimal places for order sizes, sets what size the smallest order / position on the market can be.
* @description Decimal places for order sizes, sets what size the smallest order / position on the futures market can be.
*/
readonly positionDecimalPlaces?: string;
/** @description Price monitoring parameters. */
@@ -1291,6 +1467,80 @@ export interface components {
readonly quadraticSlippageFactor?: string;
/** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */
readonly simple?: components['schemas']['vegaSimpleModelParams'];
/** @description Successor configuration. If this proposal is meant to succeed a given market, then this should be set. */
readonly successor?: components['schemas']['vegaSuccessorConfiguration'];
};
/** New spot market on Vega */
readonly vegaNewSpotMarket: {
/** @description Configuration of the new spot market. */
readonly changes?: components['schemas']['vegaNewSpotMarketConfiguration'];
};
/** Configuration for a new spot market on Vega */
readonly vegaNewSpotMarketConfiguration: {
/**
* Format: uint64
* @description Decimal places used for the new spot market, sets the smallest price increment on the book.
*/
readonly decimalPlaces?: string;
/** @description New spot market instrument configuration. */
readonly instrument?: components['schemas']['vegaInstrumentConfiguration'];
/** @description Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected. */
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
/** @description Optional new spot market metadata, tags. */
readonly metadata?: readonly string[];
/**
* Format: int64
* @description Decimal places for order sizes, sets what size the smallest order / position on the spot market can be.
*/
readonly positionDecimalPlaces?: string;
/** @description Price monitoring parameters. */
readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters'];
/** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */
readonly simple?: components['schemas']['vegaSimpleModelParams'];
/** @description Specifies parameters related to target stake calculation. */
readonly targetStakeParameters?: components['schemas']['vegaTargetStakeParameters'];
};
/** New governance transfer */
readonly vegaNewTransfer: {
/** @description Configuration for a new transfer. */
readonly changes?: components['schemas']['vegaNewTransferConfiguration'];
};
readonly vegaNewTransferConfiguration: {
/** Maximum amount to transfer */
readonly amount?: string;
/** ID of asset to transfer */
readonly asset?: string;
/**
* Specifies the account to transfer to, depending on the account type:
* Network treasury: leave empty
* Party: party's public key
* Market insurance pool: market ID
*/
readonly destination?: string;
/** Specifies the account type to transfer to: reward pool, party, network insurance pool, market insurance pool */
readonly destinationType?: components['schemas']['vegaAccountType'];
/** Maximum fraction of the source account's balance to transfer as a decimal - i.e. 0.1 = 10% of the balance */
readonly fractionOfBalance?: string;
readonly oneOff?: components['schemas']['vegaOneOffTransfer'];
readonly recurring?: components['schemas']['vegaRecurringTransfer'];
/** If network treasury, field is empty, otherwise uses the market ID */
readonly source?: string;
/** Source account type, such as network treasury, market insurance pool */
readonly sourceType?: components['schemas']['vegaAccountType'];
/**
* "All or nothing" or "best effort":
* All or nothing: Transfers the specified amount or does not transfer anything
* Best effort: Transfers the specified amount or the max allowable amount if this is less than the specified amount
*/
readonly transferType?: components['schemas']['vegaGovernanceTransferType'];
};
/** Specific details for a one off transfer */
readonly vegaOneOffTransfer: {
/**
* Format: int64
* @description Timestamp in Unix nanoseconds for when the transfer should be delivered into the receiver's account.
*/
readonly deliverOn?: string;
};
/**
* Type values for an order
@@ -1369,6 +1619,8 @@ export interface components {
};
/** Terms for a governance proposal on Vega */
readonly vegaProposalTerms: {
/** @description Cancel a governance transfer. */
readonly cancelTransfer?: components['schemas']['vegaCancelTransfer'];
/**
* Format: int64
* @description Timestamp as Unix time in seconds when voting closes for this proposal,
@@ -1388,20 +1640,39 @@ export interface components {
* and can be used to gauge community sentiment.
*/
readonly newFreeform?: components['schemas']['vegaNewFreeform'];
/** @description Proposal change for creating new market on Vega. */
/** @description Proposal change for creating new futures market on Vega. */
readonly newMarket?: components['schemas']['vegaNewMarket'];
/** @description Proposal change for creating new spot market on Vega. */
readonly newSpotMarket?: components['schemas']['vegaNewSpotMarket'];
/** @description Proposal change for a governance transfer. */
readonly newTransfer?: components['schemas']['vegaNewTransfer'];
/** @description Proposal change for updating an asset. */
readonly updateAsset?: components['schemas']['vegaUpdateAsset'];
/** @description Proposal change for modifying an existing market on Vega. */
/** @description Proposal change for modifying an existing futures market on Vega. */
readonly updateMarket?: components['schemas']['vegaUpdateMarket'];
/** @description Proposal change for updating Vega network parameters. */
readonly updateNetworkParameter?: components['schemas']['vegaUpdateNetworkParameter'];
/** @description Proposal change for modifying an existing spot market on Vega. */
readonly updateSpotMarket?: components['schemas']['vegaUpdateSpotMarket'];
/**
* Format: int64
* @description Validation timestamp as Unix time in seconds.
*/
readonly validationTimestamp?: string;
};
/** Specific details for a recurring transfer */
readonly vegaRecurringTransfer: {
/**
* Format: uint64
* @description Last epoch at which this transfer shall be paid.
*/
readonly endEpoch?: string;
/**
* Format: uint64
* @description First epoch from which this transfer shall be paid.
*/
readonly startEpoch?: string;
};
readonly vegaScalarValue: {
readonly value?: string;
};
@@ -1442,6 +1713,15 @@ export interface components {
*/
readonly probabilityOfTrading?: number;
};
/** Spot product configuration */
readonly vegaSpotProduct: {
/** @description Base asset ID. */
readonly baseAsset?: string;
/** @description Product name. */
readonly name?: string;
/** @description Quote asset ID. */
readonly quoteAsset?: string;
};
readonly vegaStakeDeposited: {
/** @description Amount deposited as an unsigned base 10 integer scaled to the asset's decimal places. */
readonly amount?: string;
@@ -1507,6 +1787,13 @@ export interface components {
readonly scalarVal?: components['schemas']['vegaScalarValue'];
readonly vectorVal?: components['schemas']['vegaVectorValue'];
};
/** @description Configuration required to turn a new market proposal in to a successor market proposal. */
readonly vegaSuccessorConfiguration: {
/** @description A decimal value between or equal to 0 and 1, specifying the fraction of the insurance pool balance that is carried over from the parent market to the successor. */
readonly insurancePoolFraction?: string;
/** @description ID of the market that the successor should take over from. */
readonly parentMarketId?: string;
};
/** TargetStakeParameters contains parameters used in target stake calculation */
readonly vegaTargetStakeParameters: {
/**
@@ -1547,14 +1834,14 @@ export interface components {
};
/** Update an existing market on Vega */
readonly vegaUpdateMarket: {
/** @description Updated configuration of the market. */
/** @description Updated configuration of the futures market. */
readonly changes?: components['schemas']['vegaUpdateMarketConfiguration'];
/** @description Market ID the update is for. */
readonly marketId?: string;
};
/** Configuration to update a market on Vega */
/** Configuration to update a futures market on Vega */
readonly vegaUpdateMarketConfiguration: {
/** @description Updated market instrument configuration. */
/** @description Updated futures market instrument configuration. */
readonly instrument?: components['schemas']['vegaUpdateInstrumentConfiguration'];
/** @description Linear slippage factor is used to cap the slippage component of maintenance margin - it is applied to the slippage volume. */
readonly linearSlippageFactor?: string;
@@ -1567,7 +1854,7 @@ export interface components {
* price levels over which automated liquidity provision orders will be deployed.
*/
readonly lpPriceRange?: string;
/** @description Optional market metadata, tags. */
/** @description Optional futures market metadata, tags. */
readonly metadata?: readonly string[];
/** @description Price monitoring parameters. */
readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters'];
@@ -1581,6 +1868,26 @@ export interface components {
/** @description The network parameter to update. */
readonly changes?: components['schemas']['vegaNetworkParameter'];
};
/** Update an existing spot market on Vega */
readonly vegaUpdateSpotMarket: {
/** @description Updated configuration of the spot market. */
readonly changes?: components['schemas']['vegaUpdateSpotMarketConfiguration'];
/** @description Market ID the update is for. */
readonly marketId?: string;
};
/** Configuration to update a spot market on Vega */
readonly vegaUpdateSpotMarketConfiguration: {
/** @description Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected. */
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
/** @description Optional spot market metadata, tags. */
readonly metadata?: readonly string[];
/** @description Price monitoring parameters. */
readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters'];
/** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */
readonly simple?: components['schemas']['vegaSimpleModelParams'];
/** @description Specifies parameters related to target stake calculation. */
readonly targetStakeParameters?: components['schemas']['vegaTargetStakeParameters'];
};
readonly vegaVectorValue: {
readonly value?: readonly string[];
};
@@ -1609,12 +1916,12 @@ export interface components {
export type external = Record<string, never>;
export interface operations {
/**
* Info
* @description Get information about the block explorer.
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built
*/
BlockExplorer_Info: {
/**
* Info
* @description Get information about the block explorer.
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built
*/
responses: {
/** @description A successful response. */
200: {
@@ -1630,19 +1937,38 @@ export interface operations {
};
};
};
/**
* List transactions
* @description List transactions from the Vega blockchain
*/
BlockExplorer_ListTransactions: {
/**
* List transactions
* @description List transactions from the Vega blockchain
*/
parameters?: {
/** @description Number of transactions to be returned from the blockchain. */
/** @description Optional cursor to paginate the request. */
/** @description Optional cursor to paginate the request. */
readonly query?: {
parameters: {
query?: {
/**
* @description Number of transactions to be returned from the blockchain.
* This is deprecated, use first and last instead.
*/
limit?: number;
/** @description Optional cursor to paginate the request. */
before?: string;
/** @description Optional cursor to paginate the request. */
after?: string;
/** @description Transaction command types filter, for listing transactions with specified command types. */
cmdTypes?: readonly string[];
/** @description Transaction command types exclusion filter, for listing all the transactions except the ones with specified command types. */
excludeCmdTypes?: readonly string[];
/** @description Party IDs filter, can be sender or receiver. */
parties?: readonly string[];
/**
* @description Number of transactions to be returned from the blockchain. Use in conjunction with the `after` cursor to paginate forwards.
* On its own, this will return the first `first` transactions.
*/
first?: number;
/**
* @description Number of transactions to be returned from the blockchain. Use in conjunction with the `before` cursor to paginate backwards.
* On its own, this will return the last `last` transactions.
*/
last?: number;
};
};
responses: {
@@ -1660,14 +1986,14 @@ export interface operations {
};
};
};
/**
* Get transaction
* @description Get a transaction from the Vega blockchain
*/
BlockExplorer_GetTransaction: {
/**
* Get transaction
* @description Get a transaction from the Vega blockchain
*/
parameters: {
/** @description Hash of the transaction */
readonly path: {
path: {
/** @description Hash of the transaction */
hash: string;
};
};
+1 -1
View File
@@ -1,5 +1,5 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nrwl/next/tailwind');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../../libs/tailwindcss-config/src/theme');
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
+2 -2
View File
@@ -5,8 +5,8 @@
"types": ["node"]
},
"files": [
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../node_modules/@nrwl/react/typings/image.d.ts"
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
"../../node_modules/@nx/react/typings/image.d.ts"
],
"exclude": [
"**/*.spec.ts",
+2 -2
View File
@@ -18,7 +18,7 @@
"jest.config.ts"
],
"files": [
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../node_modules/@nrwl/react/typings/image.d.ts"
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
"../../node_modules/@nx/react/typings/image.d.ts"
]
}
+5 -2
View File
@@ -1,6 +1,8 @@
const { composePlugins, withNx } = require('@nx/webpack');
const { withReact } = require('@nx/react');
const SentryPlugin = require('@sentry/webpack-plugin');
module.exports = (config, context) => {
module.exports = composePlugins(withNx(), withReact(), (config) => {
const additionalPlugins = process.env.SENTRY_AUTH_TOKEN
? [
new SentryPlugin({
@@ -13,5 +15,6 @@ module.exports = (config, context) => {
return {
...config,
plugins: [...additionalPlugins, ...config.plugins],
ignoreWarnings: [/Failed to parse source map/],
};
};
});
+4 -3
View File
@@ -1,10 +1,11 @@
{
"name": "governance-e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/governance-e2e/src",
"projectType": "application",
"targets": {
"e2e": {
"executor": "@nrwl/cypress:cypress",
"executor": "@nx/cypress:cypress",
"options": {
"cypressConfig": "apps/governance-e2e/cypress.config.js",
"devServerTarget": "governance:serve"
@@ -16,14 +17,14 @@
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"executor": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/governance-e2e/**/*.{js,ts}"]
}
},
"build": {
"executor": "@nrwl/workspace:run-commands",
"executor": "nx:run-commands",
"outputs": [],
"options": {
"command": "yarn tsc --project ./apps/governance-e2e/"
@@ -218,17 +218,33 @@ describe(
getProposalInformationFromTable('Tokens for proposal')
.should('have.text', (1).toFixed(2))
.and('be.visible');
navigateTo(navigation.proposals);
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() => {
// 3002-PROP-021
cy.getByTestId('user-voted-yes').should('exist');
cy.getByTestId(viewProposalButton).click();
});
});
cy.getByTestId(changeVoteButton).should('be.visible').click();
voteForProposal('against');
cy.getByTestId(proposalVoteProgressAgainstPercentage)
.contains('100.00%')
.and('be.visible');
cy.getByTestId(voteBreakdownToggle).click();
getProposalInformationFromTable('Tokens against proposal')
.should('have.text', (1).toFixed(2))
.and('be.visible');
getProposalInformationFromTable('Number of voting parties')
.should('have.text', '1')
.and('be.visible');
navigateTo(navigation.proposals);
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() => {
cy.getByTestId('user-voted-no').should('exist');
cy.getByTestId(viewProposalButton).click();
});
});
});
// 3001-VOTE-042, 3001-VOTE-057, 3001-VOTE-058, 3001-VOTE-059, 3001-VOTE-060
@@ -26,6 +26,8 @@ const votesTable = 'votes-table';
const openProposals = 'open-proposals';
const proposalVoteProgressForPercentage =
'vote-progress-indicator-percentage-for';
const majorityVoteReached = 'majority-reached';
const minParticipationReached = 'participation-reached';
const proposalTimeout = { timeout: 8000 };
context(
@@ -72,7 +74,7 @@ context(
});
});
// 3001-VOTE-046 3001-VOTE-044 3001-VOTE-074 3001-VOTE-074
// 3001-VOTE-020 3001-VOTE-021 3001-VOTE-046 3001-VOTE-044 3001-VOTE-074 3001-VOTE-074
it('Able to enact proposal by voting', function () {
const proposalTitle = 'Add New proposal with short enactment';
const proposalTx = createUpdateNetworkProposalTxBody();
@@ -85,10 +87,18 @@ context(
cy.contains(proposalTitle)
.parentsUntil(proposalListItem)
.last()
.within(() => cy.getByTestId(viewProposalButton).click());
.within(() => {
// 3001-VOTE-019 time to vote is highlighted red
cy.getByTestId('vote-details')
.find('span')
.should('have.class', 'text-vega-pink');
cy.getByTestId(viewProposalButton).click();
});
});
cy.getByTestId(proposalStatus).should('have.text', 'Open');
voteForProposal('for');
cy.getByTestId(majorityVoteReached).should('exist');
cy.getByTestId(minParticipationReached).should('exist');
cy.getByTestId(proposalStatus, proposalTimeout)
.should('have.text', 'Passed')
.then(() => {
@@ -104,6 +114,14 @@ context(
cy.getByTestId(proposalVoteProgressForPercentage)
.contains('100.00%')
.and('be.visible');
navigateTo(navigation.proposals);
cy.contains(proposalTitle)
.parentsUntil(proposalListItem)
.last()
.within(() => {
cy.getByTestId(majorityVoteReached).should('exist');
cy.getByTestId(minParticipationReached).should('exist');
});
});
// 3001-VOTE-047
@@ -320,8 +320,8 @@ context(
// 3001-VOTE-076
cy.getByTestId(connectToVegaWalletButton)
.should('be.visible')
.and('have.text', 'Connect Vega wallet')
.click();
.and('have.text', 'Connect Vega wallet');
cy.getByTestId(connectToVegaWalletButton).click();
cy.getByTestId('connector-jsonRpc').click();
cy.getByTestId(vegaWalletNameElement).should('be.visible');
cy.getByTestId(connectToVegaWalletButton).should('not.exist');
@@ -295,7 +295,7 @@ context(
// Will fail if run after 'Able to submit update market proposal and vote for proposal'
// 3002-PROP-022
it('Unable to submit update market proposal without equity-like share in the market', function () {
it.skip('Unable to submit update market proposal without equity-like share in the market', function () {
switchVegaWalletPubKey();
stakingPageAssociateTokens('1');
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
@@ -49,8 +49,8 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
navigateTo(navigation.proposals);
});
// 3001-VOTE-018
it('Newly created proposals list - proposals closest to closing date appear higher in list', function () {
// 3001-VOTE-005
const proposalDays = [364, 50, 2];
for (let index = 0; index < proposalDays.length; index++) {
goToMakeNewProposal(governanceProposalType.RAW);
@@ -120,16 +120,24 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
submitUniqueRawProposal({ proposalTitle: proposalTitle });
getProposalFromTitle(proposalTitle).within(() => {
// 3001-VOTE-039
cy.getByTestId(voteStatus).should(
cy.getByTestId('participation-not-reached').should(
'have.text',
'Participation not reached'
'Min. participation not reached'
);
cy.getByTestId(viewProposalButton).click();
});
voteForProposal('for');
navigateTo(navigation.proposals);
getProposalFromTitle(proposalTitle).within(() => {
cy.getByTestId(voteStatus).should('have.text', 'Set to pass');
cy.getByTestId(voteStatus).should(
'have.text',
'Currently expected to pass'
);
cy.getByTestId('user-voted-yes').should('exist');
cy.getByTestId('participation-reached').should(
'have.text',
'Min. participation reached'
);
cy.getByTestId(viewProposalButton).click();
});
cy.getByTestId(voteBreakDownToggle).click();
@@ -144,7 +144,7 @@ context(
closeStakingDialog();
navigateTo(navigation.validators);
cy.getByTestId(viewStakedByMeToggle).click();
cy.getByTestId(userStakeBtn).should('have.length', 2);
cy.getByTestId(userStakeBtn, epochTimeout).should('have.length', 2);
});
it('Able to stake against a validator - using vega from vesting contract', function () {
@@ -351,6 +351,12 @@ context(
);
stakingPageDisassociateAllTokens();
});
it('Able to associate over 1 million tokens', function () {
cy.get(ethWalletAssociateButton).click();
stakingPageAssociateTokens('2000000', { approve: true });
stakingPageDisassociateAllTokens();
});
});
}
);
@@ -116,7 +116,6 @@ context(
cy.getByTestId(amountInput).click().type('120');
cy.getByTestId(submitWithdrawalButton).click();
});
// assert withdrawal request
cy.getByTestId(toast)
.first(txTimeout)
.should('contain.text', 'Funds unlocked')
@@ -11,7 +11,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
cy.getByTestId('home-proposals').within(() => {
cy.get('[href="/proposals"]')
.should('exist')
.and('have.text', 'Browse, vote, and propose');
.and('have.text', 'See all proposals');
});
});
@@ -161,7 +161,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
cy.getByTestId('menu-drawer').should('be.visible');
});
it.skip('should have link for proposal page', function () {
it('should have link for proposal page', function () {
cy.getByTestId('menu-drawer').within(() => {
cy.get('[href="/proposals"]')
.should('exist')
@@ -14,6 +14,10 @@ const proposalDocsLink = 'proposal-docs-link';
const proposalDocumentationLink = 'proposal-documentation-link';
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
const governanceDocsUrl = 'https://vega.xyz/governance';
const networkUpgradeProposalListItem = 'protocol-upgrade-proposals-list-item';
const closedProposals = 'closed-proposals';
const closedProposalToggle = 'closed-proposals-toggle-networkUpgrades';
const protocolUpgradeTime = 'protocol-upgrade-time';
context(
'Governance Page - verify elements on page',
@@ -127,7 +131,7 @@ context(
mockNetworkUpgradeProposal();
cy.visit('/');
cy.getByTestId('home-proposal-list').within(() => {
cy.getByTestId('protocol-upgrade-proposals-list-item').should('exist');
cy.getByTestId(networkUpgradeProposalListItem).should('exist');
cy.getByTestId('protocol-upgrade-proposal-title').should(
'have.text',
'Vega release v1'
@@ -141,11 +145,7 @@ context(
cy.getByTestId('open-proposals').within(() => {
cy.get('li')
.eq(0)
.should(
'have.attr',
'data-testid',
'protocol-upgrade-proposals-list-item'
)
.should('have.attr', 'data-testid', networkUpgradeProposalListItem)
.within(() => {
cy.get('h2').should('have.text', 'Vega release v1');
cy.getByTestId('protocol-upgrade-proposal-type').should(
@@ -162,23 +162,24 @@ context(
);
cy.getByTestId('protocol-upgrade-proposal-status').should(
'have.text',
'Approved by validators '
'Approved by validators'
);
});
});
cy.get('[data-testid="closed-proposals-toggle-networkUpgrades"]').click();
cy.getByTestId('closed-proposals').within(() => {
cy.getByTestId('protocol-upgrade-proposals-list-item').should(
'have.length',
1
);
cy.getByTestId(closedProposals).within(() => {
cy.getByTestId(networkUpgradeProposalListItem).should('not.exist');
});
cy.getByTestId(closedProposalToggle).click();
cy.getByTestId(closedProposals).within(() => {
cy.getByTestId(networkUpgradeProposalListItem).should('have.length', 1);
});
});
// 3009-NTWU-003 3009-NTWU-004 3009-NTWU-007
it('should see details of network upgrade proposal', function () {
mockNetworkUpgradeProposal();
navigateTo(navigation.proposals);
cy.getByTestId('protocol-upgrade-proposals-list-item')
cy.getByTestId(networkUpgradeProposalListItem)
.first()
.find('[data-testid="view-proposal-btn"]')
.click();
@@ -215,5 +216,64 @@ context(
);
});
});
it('filtering proposal should not display any network upgrade proposals', function () {
const proposalId =
'd848fc7881f13d366df5f61ab139d5fcfa72bf838151bb51b54381870e357931';
mockNetworkUpgradeProposal();
navigateTo(navigation.proposals);
cy.get('[data-testid="proposal-filter-toggle"]').click();
cy.get('[data-testid="filter-input"]').type(proposalId);
cy.getByTestId(closedProposals).should('have.length', 1);
cy.getByTestId(networkUpgradeProposalListItem).should('not.exist');
cy.getByTestId(closedProposalToggle).should('not.exist');
});
// 3009-NTWU-001 3009-NTWU-002 3009-NTWU-006 3009-NTWU-009
it('should display network upgrade banner with estimate', function () {
mockNetworkUpgradeProposal();
cy.visit('/');
cy.getByTestId('banners').within(() => {
cy.get('div')
.should('contain.text', 'The network will upgrade to v1 in ')
.and(
'contain.text',
'Trading activity will be interrupted, manage your risk appropriately.'
);
cy.getByTestId('external-link')
.should('have.attr', 'href')
.and('contain', '/proposals/protocol-upgrade/v1');
});
// estimate does not display possibly due to mocks or Cypress unless the proposal is clicked on several times
// By default the application waits for 10 blocks until showing estimate - roughly 10 seconds
for (let i = 0; i < 3; i++) {
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(3000);
navigateTo(navigation.proposals);
cy.getByTestId(networkUpgradeProposalListItem)
.first()
.find('[data-testid="view-proposal-btn"]')
.click();
}
cy.getByTestId('upgrade-proposal-estimate')
.invoke('text')
.as('displayedEstimate');
cy.get('@displayedEstimate').then((estimateText) => {
// Estimated time should automatically update every second
cy.getByTestId(protocolUpgradeTime)
.invoke('text')
.should('not.eq', estimateText);
});
// time estimate on proposal detail
cy.getByTestId('protocol-upgrade-proposal').within(() => {
cy.get('@displayedEstimate').then((estimateText) => {
cy.getByTestId(protocolUpgradeTime)
.invoke('text')
.should('not.eq', estimateText);
});
});
});
}
);
@@ -1,13 +1,12 @@
/// <reference types="cypress" />
import {
navigateTo,
navigation,
turnTelemetryOff,
waitForSpinner,
} from '../../support/common.functions';
import {
enterUniqueFreeFormProposalBody,
createTenDigitUnixTimeStampForSpecifiedDays,
enterRawProposalBody,
goToMakeNewProposal,
governanceProposalType,
} from '../../support/governance.functions';
@@ -47,12 +46,11 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
.and('contain.text', 'USDC (fake)');
});
it.skip('Unable to submit proposal with public key', function () {
it('Unable to submit proposal with public key', function () {
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
navigateTo(navigation.proposals);
goToMakeNewProposal(governanceProposalType.FREEFORM);
enterUniqueFreeFormProposalBody('50', 'pub key proposal test');
goToMakeNewProposal(governanceProposalType.RAW);
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
cy.getByTestId('dialog-content')
.first()
.within(() => {
@@ -78,7 +78,7 @@ context(
cy.getByTestId('connector-jsonRpc')
.should('be.visible')
.and('have.text', 'Connect Vega wallet');
cy.getByTestId('connector-hosted')
cy.getByTestId('connector-rest')
.should('be.visible')
.and('have.text', 'Hosted Fairground wallet');
});
@@ -94,7 +94,7 @@ context(
describe('when rest connector form opened', function () {
before('click hosted wallet app button', function () {
cy.getByTestId(connectorsList).within(() => {
cy.getByTestId('connector-hosted').click();
cy.getByTestId('connector-rest').click();
});
});
@@ -340,7 +340,7 @@ context(
.contains(name)
.parent()
.siblings()
.then((elementAmount) => {
.should((elementAmount) => {
const displayedAmount = parseFloat(elementAmount.text());
expect(displayedAmount).be.gte(expectedAmount);
});
@@ -174,7 +174,8 @@ export function clickOnValidatorFromList(
cy.get(`[row-id="${validatorNumber}"]`)
.should('be.visible')
.find(stakeValidatorListName)
.click();
.as('validatorOnList');
cy.get('@validatorOnList').click();
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"presets": [
[
"@nrwl/react/babel",
"@nx/react/babel",
{
"runtime": "automatic"
}
+6
View File
@@ -18,6 +18,12 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
#Test configuration variables
CYPRESS_FAIRGROUND=false
LC_ALL="en_US.UTF-8"
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
+5
View File
@@ -19,6 +19,11 @@ NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
NX_VEGA_REST_URL=http://localhost:3008/api/v2/
NX_TENDERMINT_URL=http://localhost:26617
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
#Test configuration variables
CYPRESS_FAIRGROUND=false
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
+6
View File
@@ -13,3 +13,9 @@ NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_REST_URL=https://api.n00.devnet1.vega.xyz/api/v2/
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
+6
View File
@@ -14,3 +14,9 @@ NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_REST_URL=https://api.vega.community/api/v2/
NX_TENDERMINT_URL=https://be.vega.community
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
+21
View File
@@ -0,0 +1,21 @@
# App configuration variables
NX_VEGA_ENV=MAINNET_MIRROR
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz","MAINNET_MIRROR":"https://governance.mainnet-mirror.vega.rocks","STAGNET1":"https://trading.stagnet1.vega.rocks"}'
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-mirror-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_REST_URL=https://api.mainnet-mirror.vega.rocks/api/v2/
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
+6
View File
@@ -9,3 +9,9 @@ NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
+6
View File
@@ -14,3 +14,9 @@ NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
+6
View File
@@ -11,3 +11,9 @@ NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
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_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
+2 -2
View File
@@ -1,6 +1,6 @@
{
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "__generated__"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+2 -1
View File
@@ -25,13 +25,14 @@ yarn nx serve governance
Example configurations are provided here:
- [Mainnet](./.env.mainnet)
- [Mainnet-mirror](./.env.mainnet-mirror)
- [Devnet](./.env.devnet)
- [Testnet](./.env.testnet)
For convenience, you can boot the app injecting one of the configurations above by running:
```bash
yarn nx run governance:serve --env={env} # e.g. stagnet1
yarn env-cmd -f .\apps\governance\.env.{env} yarn nx run governance:serve # e.g. stagnet1
```
There are a few different configuration options offered for this app:
+2 -3
View File
@@ -3,8 +3,8 @@ export default {
displayName: 'governance',
preset: '../../jest.preset.js',
transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
'^.+\\.[tj]sx?$': 'babel-jest',
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/apps/governance',
@@ -16,6 +16,5 @@ export default {
'**/*.{ts,tsx}',
'!**/node_modules/**',
'!**/__generated__/**',
'!**/__generated___/**',
],
};
+14 -7
View File
@@ -1,10 +1,11 @@
{
"name": "governance",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/governance/src",
"projectType": "application",
"targets": {
"build": {
"executor": "./tools/executors/webpack:build",
"executor": "@nx/webpack:webpack",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
@@ -41,7 +42,7 @@
}
},
"serve": {
"executor": "./tools/executors/webpack:serve",
"executor": "@nx/webpack:dev-server",
"options": {
"port": 4210,
"buildTarget": "governance:build:development",
@@ -55,22 +56,28 @@
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"executor": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/governance/**/*.{ts,tsx,js,jsx}"]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["coverage/apps/governance"],
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/apps/governance"],
"options": {
"jestConfig": "apps/governance/jest.config.ts",
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
},
"build-netlify": {
"executor": "@nrwl/workspace:run-commands",
"executor": "nx:run-commands",
"options": {
"commands": [
"cp apps/governance/netlify.toml netlify.toml",
@@ -79,7 +86,7 @@
}
},
"build-spec": {
"executor": "@nrwl/workspace:run-commands",
"executor": "nx:run-commands",
"outputs": [],
"options": {
"command": "yarn tsc --project ./apps/governance/tsconfig.spec.json"
+4 -5
View File
@@ -2,14 +2,13 @@ import * as Sentry from '@sentry/react';
import { toBigNum } from '@vegaprotocol/utils';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet, useEagerConnect } from '@vegaprotocol/wallet';
import { useEnvironment } from '@vegaprotocol/environment';
import { FLAGS, useEnvironment } from '@vegaprotocol/environment';
import { useWeb3React } from '@web3-react/core';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { SplashError } from './components/splash-error';
import { SplashLoader } from './components/splash-loader';
import { Flags } from './config';
import {
AppStateActionType,
useAppState,
@@ -80,7 +79,7 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
}
};
if (!Flags.NETWORK_DOWN) {
if (!FLAGS.GOVERNANCE_NETWORK_DOWN) {
run();
}
}, [token, appDispatch, staking, vesting]);
@@ -148,7 +147,7 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
};
// Only begin polling if network limits flag is set, as this is a new API not yet on mainnet 7/3/22
if (Flags.NETWORK_LIMITS) {
if (FLAGS.GOVERNANCE_NETWORK_LIMITS) {
getNetworkLimits();
}
@@ -157,7 +156,7 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
};
}, [appDispatch, VEGA_URL, t]);
if (Flags.NETWORK_DOWN) {
if (FLAGS.GOVERNANCE_NETWORK_DOWN) {
return (
<Splash>
<SplashError />
@@ -2,13 +2,8 @@ import { Button } from '@vegaprotocol/ui-toolkit';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import {
AppStateActionType,
useAppState,
} from '../../contexts/app-state/app-state-context';
export const ConnectToVega = () => {
const { appDispatch } = useAppState();
const { t } = useTranslation();
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
@@ -16,10 +11,6 @@ export const ConnectToVega = () => {
return (
<Button
onClick={() => {
appDispatch({
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
isOpen: true,
});
openVegaWalletDialog();
}}
data-testid="connect-to-vega-wallet-btn"
@@ -0,0 +1 @@
export * from './json-diff';
@@ -0,0 +1,30 @@
import { render, screen, cleanup } from '@testing-library/react';
import { JsonDiff } from './json-diff';
describe('JsonDiff', () => {
afterEach(cleanup);
it('renders without crashing', () => {
render(<JsonDiff left={{}} right={{}} />);
expect(screen.getByTestId('json-diff')).toBeInTheDocument();
});
it('shows the correct message when both objects are identical', () => {
render(<JsonDiff left={{}} right={{}} />);
expect(screen.getByText('Data is identical')).toBeInTheDocument();
});
it('does not show the "identical" message when both objects are not identical', () => {
render(
<JsonDiff
left={{
name: 'test',
}}
right={{
name: 'test2',
}}
/>
);
expect(screen.queryByText('Data is identical')).not.toBeInTheDocument();
});
});
@@ -0,0 +1,46 @@
import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { formatters, create } from 'jsondiffpatch';
import 'jsondiffpatch/dist/formatters-styles/html.css';
import 'jsondiffpatch/dist/formatters-styles/annotated.css';
export type JsonValue =
| string
| number
| boolean
| null
| JsonValue[]
| { [key: string]: JsonValue };
interface JsonDiffProps {
left: JsonValue;
right: JsonValue;
objectHash?: (obj: unknown) => string | undefined;
}
export const JsonDiff = ({ right, left, objectHash }: JsonDiffProps) => {
const { t } = useTranslation();
const [html, setHtml] = useState<string | undefined>();
useEffect(() => {
const delta = create({
objectHash,
}).diff(left, right);
if (delta) {
const deltaHtml = formatters.html.format(delta, left);
formatters.html.hideUnchanged();
setHtml(deltaHtml);
} else {
setHtml(undefined);
}
}, [right, left, objectHash]);
return html ? (
<div data-testid="json-diff" dangerouslySetInnerHTML={{ __html: html }} />
) : (
<p data-testid="json-diff">{t('dataIsIdentical')}</p>
);
};
+7 -1
View File
@@ -18,6 +18,7 @@ import { VegaWallet } from '../vega-wallet';
import { useLocation, useMatch } from 'react-router-dom';
import { useEffect } from 'react';
import { useTelemetryDialog } from '../telemetry-dialog/telemetry-dialog';
import { ProtocolUpgradeCountdown } from '@vegaprotocol/proposals';
export const SettingsLink = () => {
const { open, isOpen, close } = useTelemetryDialog();
@@ -61,7 +62,12 @@ export const Nav = ({ theme }: Pick<NavigationProps, 'theme'>) => {
appName="Governance"
theme={theme}
breakpoints={[458, 959]}
actions={<SettingsLink />}
actions={
<>
<SettingsLink />
<ProtocolUpgradeCountdown />
</>
}
>
<NavigationList
className="[.drawer-content_&]:border-b [.drawer-content_&]:border-b-vega-light-200 dark:[.drawer-content_&]:border-b-vega-dark-200 [.drawer-content_&]:pb-8 [.drawer-content_&]:mb-2"
@@ -4,7 +4,11 @@ import type { ReactNode } from 'react';
import { AnnouncementBanner } from '@vegaprotocol/announcements';
import { Nav } from '../nav';
import { Networks, useEnvironment } from '@vegaprotocol/environment';
import React from 'react';
import {
ProtocolUpgradeCountdownMode,
ProtocolUpgradeProposalNotification,
} from '@vegaprotocol/proposals';
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
interface AppLayoutProps {
children: ReactNode;
@@ -31,8 +35,23 @@ export const AppLayout = ({ children }: AppLayoutProps) => {
/>
)}
<Nav theme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'} />
<NotificationsContainer />
</div>
<div className={AppLayoutClasses}>{children}</div>
</div>
);
};
const NotificationsContainer = () => {
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
return (
<div data-testid="banners">
<ProtocolUpgradeProposalNotification
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
/>
{isReadOnly ? (
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
) : null}
</div>
);
};
@@ -1,5 +1,3 @@
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import React from 'react';
export interface TemplateSidebarProps {
@@ -8,24 +6,18 @@ export interface TemplateSidebarProps {
}
export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
return (
<>
{isReadOnly ? (
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
) : null}
<div className="w-full border-b border-neutral-700 lg:grid lg:grid-rows-[1fr] lg:grid-cols-[1fr_450px]">
<main className="max-w-[100vw] col-start-1 p-4 overflow-auto">
{children}
</main>
<aside className="col-start-2 row-start-1 row-span-2 hidden lg:block p-4 bg-banner bg-contain border-l border-neutral-700">
{sidebar.map((Component, i) => (
<section className="mb-4 last:mb-0" key={i}>
{Component}
</section>
))}
</aside>
</div>
</>
<div className="w-full border-b border-neutral-700 lg:grid lg:grid-rows-[1fr] lg:grid-cols-[1fr_450px]">
<main className="max-w-[100vw] col-start-1 p-4 overflow-auto">
{children}
</main>
<aside className="col-start-2 row-start-1 row-span-2 hidden lg:block p-4 bg-banner bg-contain border-l border-neutral-700">
{sidebar.map((Component, i) => (
<section className="mb-4 last:mb-0" key={i}>
{Component}
</section>
))}
</aside>
</div>
);
}
@@ -3,11 +3,6 @@ import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import React from 'react';
import { useTranslation } from 'react-i18next';
import {
AppStateActionType,
useAppState,
} from '../../contexts/app-state/app-state-context';
interface VegaWalletContainerProps {
children: (key: string) => React.ReactElement;
}
@@ -15,7 +10,6 @@ interface VegaWalletContainerProps {
export const VegaWalletContainer = ({ children }: VegaWalletContainerProps) => {
const { t } = useTranslation();
const { pubKey } = useVegaWallet();
const { appDispatch } = useAppState();
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
@@ -25,10 +19,6 @@ export const VegaWalletContainer = ({ children }: VegaWalletContainerProps) => {
<Button
data-testid="connect-to-vega-wallet-btn"
onClick={() => {
appDispatch({
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
isOpen: true,
});
openVegaWalletDialog();
}}
>
@@ -13,12 +13,6 @@ export const VegaWalletDialogs = () => {
<>
<VegaConnectDialog
connectors={Connectors}
onChangeOpen={(open) =>
appDispatch({
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
isOpen: open,
})
}
riskMessage={<RiskMessage />}
/>
@@ -71,7 +71,6 @@ export const VegaWallet = () => {
const VegaWalletNotConnected = () => {
const { t } = useTranslation();
const { appDispatch } = useAppState();
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
@@ -79,10 +78,6 @@ const VegaWalletNotConnected = () => {
<>
<Button
onClick={() => {
appDispatch({
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
isOpen: true,
});
openVegaWalletDialog();
}}
fill={true}
+4 -6
View File
@@ -25,6 +25,10 @@ export const ContractAddresses: {
claimAddress: customClaimAddress ?? '0x0',
lockedAddress: customLockedAddress ?? '0x0',
},
MAINNET_MIRROR: {
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
lockedAddress: '0x0', // TODO not deployed to this env
},
DEVNET: {
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
lockedAddress: '0x0', // TODO not deployed to this env
@@ -63,12 +67,6 @@ export const ENV = {
localProviderUrl: windowOrDefault('NX_LOCAL_PROVIDER_URL'),
delegationsPagination: windowOrDefault('NX_DELEGATIONS_PAGINATION'),
rest: windowOrDefault('NX_VEGA_REST_URL'),
flags: {
NETWORK_DOWN: TRUTHY.includes(windowOrDefault('NX_NETWORK_DOWN')),
MOCK: TRUTHY.includes(windowOrDefault('NX_MOCKED')),
FAIRGROUND: TRUTHY.includes(windowOrDefault('NX_FAIRGROUND')),
NETWORK_LIMITS: TRUTHY.includes(windowOrDefault('NX_NETWORK_LIMITS')),
},
addresses:
ContractAddresses[(envName === 'local' ? 'CUSTOM' : envName) as Networks],
};
-5
View File
@@ -1,5 +0,0 @@
import { ENV } from './env';
export const Flags = {
...ENV.flags,
};
-1
View File
@@ -1,2 +1 @@
export * from './flags';
export * from './env';

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