Compare commits
375
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cab087449b | ||
|
|
01842a78b0 | ||
|
|
c27f08c672 | ||
|
|
58cc074538 | ||
|
|
852c9bb8f4 | ||
|
|
efe9b7a0e7 | ||
|
|
695a059dde | ||
|
|
5d7e4d273a | ||
|
|
b137e024c6 | ||
|
|
6651ee52b4 | ||
|
|
0d14722c5d | ||
|
|
4968b537b8 | ||
|
|
5f5c45f3b9 | ||
|
|
6b10df015d | ||
|
|
6d7e24732b | ||
|
|
b33cf04e16 | ||
|
|
66ebb26b0f | ||
|
|
51c88d2fce | ||
|
|
2786a984b0 | ||
|
|
39c53a7326 | ||
|
|
3371e8e2cc | ||
|
|
5843a36851 | ||
|
|
68b4909dff | ||
|
|
da8e382454 | ||
|
|
81ebefc329 | ||
|
|
1ed7d6fda2 | ||
|
|
a2e4f34b0d | ||
|
|
3a1bb855aa | ||
|
|
b4ca0a8390 | ||
|
|
349c790ecc | ||
|
|
4c8a15cc01 | ||
|
|
f433a030ff | ||
|
|
63a6e4ecbd | ||
|
|
555f6e2a6d | ||
|
|
c116762865 | ||
|
|
b47bd49e83 | ||
|
|
4b942cfb7d | ||
|
|
c27443fc13 | ||
|
|
6dbde76c84 | ||
|
|
f4abd7cef5 | ||
|
|
3b978118dc | ||
|
|
bb4cc1e51d | ||
|
|
797db6ee93 | ||
|
|
6e7b87d9ef | ||
|
|
6965bdf0ca | ||
|
|
f4d46efff5 | ||
|
|
d510330c6b | ||
|
|
5b5765ef63 | ||
|
|
283f654a4c | ||
|
|
6945514b49 | ||
|
|
f74687d30c | ||
|
|
2a7574bd8e | ||
|
|
872f1d300f | ||
|
|
600ea0eeab | ||
|
|
7c3f7a7ab1 | ||
|
|
539abce8af | ||
|
|
60ca6c2eb6 | ||
|
|
eeff4ffcd4 | ||
|
|
73ae00f12c | ||
|
|
ee73e4d5e2 | ||
|
|
14928d318d | ||
|
|
a19ea1c939 | ||
|
|
c65c296db2 | ||
|
|
6c5cd85d96 | ||
|
|
8efadda98c | ||
|
|
0872a14f44 | ||
|
|
8b249e1917 | ||
|
|
13817e4d57 | ||
|
|
abb771e2f9 | ||
|
|
acf1d50d0f | ||
|
|
9da704c117 | ||
|
|
d262650258 | ||
|
|
30da1663eb | ||
|
|
79cbe62774 | ||
|
|
df11401b69 | ||
|
|
2f0be0bf34 | ||
|
|
5b5802104e | ||
|
|
3a149ddfb2 | ||
|
|
0e519f4d0e | ||
|
|
ff2e2574f6 | ||
|
|
9b52cecf21 | ||
|
|
478cc9e753 | ||
|
|
18f1fbd56d | ||
|
|
ccb22f02c3 | ||
|
|
015d8f51c0 | ||
|
|
e2a72cb395 | ||
|
|
0669696b6f | ||
|
|
56c662e5ba | ||
|
|
7fe269fad6 | ||
|
|
b761023069 | ||
|
|
7453acd632 | ||
|
|
1f507facba | ||
|
|
9d6b34963a | ||
|
|
7ac3a68ac9 | ||
|
|
2640ccb20a | ||
|
|
77c0894501 | ||
|
|
60d7cf3029 | ||
|
|
2b8abde938 | ||
|
|
2005f19d50 | ||
|
|
d78de10855 | ||
|
|
bb402c02f6 | ||
|
|
8a9b1c7874 | ||
|
|
a7e8b0eb01 | ||
|
|
89b3c06107 | ||
|
|
cd5c73d3fd | ||
|
|
b3a5ab022d | ||
|
|
ba438549bc | ||
|
|
496d1f5c68 | ||
|
|
e914e7bb70 | ||
|
|
71a36c2382 | ||
|
|
1c6a307bcd | ||
|
|
ef4a740b91 | ||
|
|
a6303456c5 | ||
|
|
2d4be5fcb3 | ||
|
|
9cbd6baccd | ||
|
|
525773773a | ||
|
|
45d6f43e74 | ||
|
|
41760f2956 | ||
|
|
3d2b171de7 | ||
|
|
39a041332b | ||
|
|
4c0d05844e | ||
|
|
bf8480fed4 | ||
|
|
44434a7d39 | ||
|
|
b818e9b2a1 | ||
|
|
775835c667 | ||
|
|
3e30f053ff | ||
|
|
5db3453ba5 | ||
|
|
0b1987d4ce | ||
|
|
290b7ae856 | ||
|
|
835f2b793f | ||
|
|
e1557f51ce | ||
|
|
c98e53a984 | ||
|
|
95a51fd152 | ||
|
|
d50b988b4a | ||
|
|
76ee58e473 | ||
|
|
a6aec899c8 | ||
|
|
a6672d213f | ||
|
|
62f368da10 | ||
|
|
f3e2fe746d | ||
|
|
8b19572dc9 | ||
|
|
80399d04f7 | ||
|
|
8322fc7edd | ||
|
|
46752816ec | ||
|
|
f99f78780c | ||
|
|
f7037bca80 | ||
|
|
ba39720f05 | ||
|
|
6d35f2b39d | ||
|
|
78afecc2e5 | ||
|
|
3de5b07495 | ||
|
|
e944d3e37c | ||
|
|
5596392835 | ||
|
|
5c57106c04 | ||
|
|
2fc688f477 | ||
|
|
9ea8c839db | ||
|
|
d7e2da7a54 | ||
|
|
b29c268257 | ||
|
|
01ca05a313 | ||
|
|
e3c6dd41c9 | ||
|
|
fbd01dc1bd | ||
|
|
af6719cc9d | ||
|
|
c433a4ee06 | ||
|
|
e3a00ada05 | ||
|
|
aa38e0c001 | ||
|
|
86da521da5 | ||
|
|
c6df34fe95 | ||
|
|
c7d0803164 | ||
|
|
250a654544 | ||
|
|
7f5e8ebb15 | ||
|
|
ccbe34e172 | ||
|
|
27e8ce88bf | ||
|
|
41804d9869 | ||
|
|
293288286b | ||
|
|
a77765b1e9 | ||
|
|
2453d7841a | ||
|
|
a0945be721 | ||
|
|
84e40ccb2b | ||
|
|
a868f6d2f5 | ||
|
|
8b83c51014 | ||
|
|
bf7aacf984 | ||
|
|
5183f2591b | ||
|
|
b3308439bd | ||
|
|
719d210219 | ||
|
|
f810a3a0b1 | ||
|
|
db19ee80ac | ||
|
|
45623f33c5 | ||
|
|
08e204fe31 | ||
|
|
81f7b0595e | ||
|
|
4ed0e3a056 | ||
|
|
47a84b4dac | ||
|
|
c540d4b17f | ||
|
|
f1fa3250a4 | ||
|
|
707c00def2 | ||
|
|
78aff54360 | ||
|
|
6160fd7638 | ||
|
|
c345623a06 | ||
|
|
e9173796f5 | ||
|
|
2a0811863f | ||
|
|
4f610bbd1b | ||
|
|
104b2d145d | ||
|
|
f75787562c | ||
|
|
678c9090c7 | ||
|
|
21bb6a69c6 | ||
|
|
467ed5d53d | ||
|
|
d268088e60 | ||
|
|
1208d3f2a8 | ||
|
|
b5ba4f99d9 | ||
|
|
66f25603d3 | ||
|
|
4afd469404 | ||
|
|
9e5bc9c8d1 | ||
|
|
e41aff88b1 | ||
|
|
9209074332 | ||
|
|
39e5836edb | ||
|
|
85a4981700 | ||
|
|
247927e939 | ||
|
|
6523490d96 | ||
|
|
105a758e8d | ||
|
|
559ef48d6d | ||
|
|
255c3752f2 | ||
|
|
2bbf1e2b81 | ||
|
|
06d3ef8d73 | ||
|
|
de4c7926c2 | ||
|
|
50959b4c50 | ||
|
|
a8c2f4e025 | ||
|
|
2cea73c567 | ||
|
|
b0a54be408 | ||
|
|
d1a036e53c | ||
|
|
9ac199f59a | ||
|
|
332cc302c3 | ||
|
|
4da0e9c368 | ||
|
|
13e1f99767 | ||
|
|
5c18c898b0 | ||
|
|
4fe81cc4aa | ||
|
|
0fb8ee3abb | ||
|
|
3422b99491 | ||
|
|
287e294281 | ||
|
|
dc959025c6 | ||
|
|
63bfcc8f65 | ||
|
|
952e906eac | ||
|
|
e765c247ef | ||
|
|
52dea6d0dc | ||
|
|
97f243e5f7 | ||
|
|
9992d9f053 | ||
|
|
3e26431e8f | ||
|
|
6a9f15f59e | ||
|
|
4684745382 | ||
|
|
927e21b045 | ||
|
|
570472b739 | ||
|
|
28f7bd36e7 | ||
|
|
0f3e5595ba | ||
|
|
d3dbdd2bd5 | ||
|
|
0767139712 | ||
|
|
250492a02c | ||
|
|
29f3374c61 | ||
|
|
ba7b574a07 | ||
|
|
afd8650657 | ||
|
|
78414b4429 | ||
|
|
e0a91b3850 | ||
|
|
80f7a08765 | ||
|
|
3e627ff849 | ||
|
|
d2854b6e90 | ||
|
|
6d130c9cfc | ||
|
|
ab4f4e9084 | ||
|
|
fa1825ca64 | ||
|
|
206c6c7207 | ||
|
|
5b0bd69710 | ||
|
|
546b710093 | ||
|
|
afbf62be84 | ||
|
|
ef26d03d36 | ||
|
|
7471116ebf | ||
|
|
7142fc956c | ||
|
|
611f8d7491 | ||
|
|
f3b72b894e | ||
|
|
140f16f637 | ||
|
|
cae1fc67a4 | ||
|
|
35e25d9a8f | ||
|
|
86e122389c | ||
|
|
6616aceebb | ||
|
|
c937a9df0c | ||
|
|
9fcf286e4b | ||
|
|
e3ed71bec4 | ||
|
|
809f149df9 | ||
|
|
e4eedf5ccd | ||
|
|
20cbcb8302 | ||
|
|
cd3acf8ff9 | ||
|
|
30735388e8 | ||
|
|
478c4f83bb | ||
|
|
431fab8824 | ||
|
|
83b6d3d295 | ||
|
|
98fd79bc35 | ||
|
|
39aa27f332 | ||
|
|
bf4fb29fe6 | ||
|
|
5ed1befc53 | ||
|
|
1b311a8b36 | ||
|
|
70c3bc8128 | ||
|
|
7e49836875 | ||
|
|
d624957e6d | ||
|
|
069b57d4ae | ||
|
|
6894fe1264 | ||
|
|
93e4b5fdb9 | ||
|
|
1566fc3984 | ||
|
|
39962a0246 | ||
|
|
8d31510d5e | ||
|
|
26d5a67604 | ||
|
|
9cc8f5a377 | ||
|
|
2e11cf4dfa | ||
|
|
9e4ba9f275 | ||
|
|
aac0c25d09 | ||
|
|
d20c2a08ae | ||
|
|
4e6ba5fe3d | ||
|
|
276d1d7c7b | ||
|
|
4990c5808d | ||
|
|
cdd91c24f2 | ||
|
|
e3eb13ca72 | ||
|
|
3f0ebbf33d | ||
|
|
026aa3964b | ||
|
|
aa4c5a4a57 | ||
|
|
0874314d2a | ||
|
|
a70a7bcc8e | ||
|
|
4461a6a497 | ||
|
|
1041864ad8 | ||
|
|
015e0188ec | ||
|
|
228236c152 | ||
|
|
cd6e906dc6 | ||
|
|
8a47a92dbd | ||
|
|
af14c27df9 | ||
|
|
38edcd88c0 | ||
|
|
a74cf02030 | ||
|
|
6686755763 | ||
|
|
79cf8163be | ||
|
|
1688e26f4b | ||
|
|
5e101a8eaf | ||
|
|
65071f57d0 | ||
|
|
b87c981a90 | ||
|
|
b509e5b347 | ||
|
|
bb9fce4831 | ||
|
|
918825aca8 | ||
|
|
74bf183fad | ||
|
|
674baa1ee3 | ||
|
|
d18a0c7e15 | ||
|
|
76a6005b77 | ||
|
|
79414614c2 | ||
|
|
fde49e5446 | ||
|
|
45283161aa | ||
|
|
375d447fa8 | ||
|
|
1dd97a2bce | ||
|
|
d4a1a9b193 | ||
|
|
376c5241a8 | ||
|
|
8e6d8517cf | ||
|
|
5f9ec222c1 | ||
|
|
8954c41c0a | ||
|
|
4414ab4f47 | ||
|
|
d1d4bacc68 | ||
|
|
f476688c7f | ||
|
|
8845222700 | ||
|
|
e64c464091 | ||
|
|
b2c2d0d7d6 | ||
|
|
1fb61d313c | ||
|
|
ccf5ff632c | ||
|
|
54d6aaf56f | ||
|
|
736b262947 | ||
|
|
6a07127185 | ||
|
|
45f0ba7c0e | ||
|
|
6f4ea68778 | ||
|
|
90dda20891 | ||
|
|
278eb01c2f | ||
|
|
c3157de146 | ||
|
|
d28db485c5 | ||
|
|
caa0076396 | ||
|
|
451da40ed2 | ||
|
|
47694e7b72 | ||
|
|
e01fb7f9ae | ||
|
|
ffcdfb6a6a | ||
|
|
86f0d013bb | ||
|
|
c12ac45890 | ||
|
|
47ce68455a |
+2
-1
@@ -51,7 +51,8 @@
|
|||||||
"ul": ["list"],
|
"ul": ["list"],
|
||||||
"ol": ["list"]
|
"ol": ["list"]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"no-console": ["error", { "allow": ["warn", "error"] }]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
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: 'FEATURE 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:
|
jobs:
|
||||||
after-release:
|
after-release:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
timeout-minutes: 30
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -30,18 +30,20 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
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
|
- name: resolve ipfs hashes for release
|
||||||
run: |
|
run: |
|
||||||
echo "Name: ${{ github.event.release.name }}"
|
echo "Name: ${{ github.event.release.name }}"
|
||||||
echo "Description: ${{ github.event.release.body }}"
|
echo "Description: ${{ github.event.release.body }}"
|
||||||
echo "Tag: ${{ github.event.release.tag_name }}"
|
echo "Tag: ${{ github.event.release.tag_name }}"
|
||||||
commit="$(git rev-list -n 1 ${{ github.event.release.tag_name }})"
|
docker run --rm vegaprotocol/trading:mainnet cat /ipfs-hash > ipfs-hash
|
||||||
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
|
|
||||||
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
|
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
|
||||||
tar -xzf kubo.tgz
|
tar -xzf kubo.tgz
|
||||||
export PATH="$PATH:$PWD/kubo"
|
export PATH="$PATH:$PWD/kubo"
|
||||||
@@ -80,3 +82,38 @@ jobs:
|
|||||||
https://${{ env.IPFS_V1 }}.ipfs.dweb.link/
|
https://${{ env.IPFS_V1 }}.ipfs.dweb.link/
|
||||||
https://${{ env.IPFS_V1 }}.ipfs.cf-ipfs.com/
|
https://${{ env.IPFS_V1 }}.ipfs.cf-ipfs.com/
|
||||||
ipfs://${{ env.IPFS_V0 }}/
|
ipfs://${{ env.IPFS_V0 }}/
|
||||||
|
|
||||||
|
- name: Ensure 'Released' label exists
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
REPO="${{ github.repository }}"
|
||||||
|
LABEL_EXIST=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||||
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
|
"https://api.github.com/repos/$REPO/labels/Released")
|
||||||
|
if [[ "$LABEL_EXIST" == *"Not Found"* ]]; then
|
||||||
|
curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||||
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
|
-X POST "https://api.github.com/repos/$REPO/labels" \
|
||||||
|
-d '{"name": "Released", "color": "FFFFFF"}'
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Extract issues from release notes
|
||||||
|
id: extract-issues
|
||||||
|
run: |
|
||||||
|
ISSUES=$(echo "${{ github.event.release.body }}" | grep -o -E '#[0-9]+' | tr -d '#' | jq -R . | jq -cs .)
|
||||||
|
echo "Issues to label: $ISSUES"
|
||||||
|
echo "::set-output name=issue_numbers::$ISSUES"
|
||||||
|
|
||||||
|
- name: Add 'Released' label to issues
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
ISSUE_NUMBERS="${{ steps.extract-issues.outputs.issue_numbers }}"
|
||||||
|
REPO="${{ github.repository }}"
|
||||||
|
for ISSUE in $(echo "$ISSUE_NUMBERS" | jq -r '.[]'); do
|
||||||
|
curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||||
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
|
-X POST "https://api.github.com/repos/$REPO/issues/$ISSUE/labels" \
|
||||||
|
-d '{"labels": ["Released"]}'
|
||||||
|
done
|
||||||
|
|||||||
+130
-152
@@ -5,15 +5,17 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- release/*
|
- release/*
|
||||||
- develop
|
- develop
|
||||||
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
- ready_for_review
|
- ready_for_review
|
||||||
- reopened
|
- reopened
|
||||||
- edited
|
|
||||||
- synchronize
|
- synchronize
|
||||||
jobs:
|
jobs:
|
||||||
node-modules:
|
node-modules:
|
||||||
|
# All jobs depend on node_modules, so none should run if the PR is in draft
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
name: 'Cache yarn modules'
|
name: 'Cache yarn modules'
|
||||||
steps:
|
steps:
|
||||||
@@ -21,7 +23,6 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Cache node modules
|
- name: Cache node modules
|
||||||
id: cache
|
id: cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -39,23 +40,15 @@ jobs:
|
|||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
|
||||||
- name: yarn install
|
- name: yarn install
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
run: yarn install --pure-lockfile
|
run: yarn install --pure-lockfile
|
||||||
|
|
||||||
lint-pr-title:
|
lint-format:
|
||||||
needs: node-modules
|
timeout-minutes: 20
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
name: Verify PR title
|
|
||||||
uses: ./.github/workflows/lint-pr.yml
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
lint-test-build:
|
|
||||||
timeout-minutes: 60
|
|
||||||
needs: node-modules
|
needs: node-modules
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
name: '(CI) lint + unit test + build'
|
name: '(CI) lint + format check'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -90,132 +83,85 @@ jobs:
|
|||||||
- name: Build affected spec
|
- name: Build affected spec
|
||||||
run: yarn nx affected --target=build-spec
|
run: yarn nx affected --target=build-spec
|
||||||
|
|
||||||
|
test-affected:
|
||||||
|
timeout-minutes: 30
|
||||||
|
needs: build-sources
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
name: 'run unit test of affected apps'
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
|
- name: Setup node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version-file: '.nvmrc'
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
|
- name: Cache node modules
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: node_modules
|
||||||
|
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
||||||
|
|
||||||
|
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||||
|
uses: nrwl/nx-set-shas@v3
|
||||||
|
with:
|
||||||
|
main-branch-name: develop
|
||||||
|
|
||||||
- name: Test affected
|
- name: Test affected
|
||||||
run: yarn nx affected:test
|
run: yarn nx affected:test
|
||||||
|
|
||||||
- name: Build affected
|
build-sources:
|
||||||
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
timeout-minutes: 30
|
||||||
|
needs: lint-format
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
name: 'Build sources of affected apps'
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
|
- name: Setup node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version-file: '.nvmrc'
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
|
- name: Cache node modules
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: node_modules
|
||||||
|
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
||||||
|
|
||||||
|
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||||
|
uses: nrwl/nx-set-shas@v3
|
||||||
|
with:
|
||||||
|
main-branch-name: develop
|
||||||
|
|
||||||
# See affected apps
|
# See affected apps
|
||||||
- name: See affected apps
|
- name: See affected apps
|
||||||
run: |
|
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 )"
|
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 }}"
|
||||||
|
|
||||||
echo ">>>> debug"
|
- name: Verify script result
|
||||||
echo "NX_BASE: ${{ env.NX_BASE }}"
|
run: |
|
||||||
echo "NX_HEAD: ${{ env.NX_HEAD }}"
|
echo "Check outputs from script"
|
||||||
echo "Affected: ${affected}"
|
echo "projects: ${{ env.PROJECTS }}"
|
||||||
echo "Branch slug: ${branch_slug}"
|
echo "projects-e2e: ${{ env.PROJECTS_E2E }}"
|
||||||
echo "Current ref: ${{ github.ref }}"
|
echo "preview_governance: ${{ env.PREVIEW_GOVERNANCE }}"
|
||||||
echo ">>>> eof debug"
|
echo "preview_trading: ${{ env.PREVIEW_TRADING }}"
|
||||||
|
echo "preview_explorer: ${{ env.PREVIEW_EXPLORER }}"
|
||||||
projects_array=()
|
echo "preview_tools: ${{ env.PREVIEW_TOOLS }}"
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# if branch starts with release/ and ends with trading / governance or explorer - overwrite the array of affected projects with fixed single application
|
|
||||||
if [[ "${{ github.ref }}" == *release* ]]; then
|
|
||||||
echo ">> This is a relase branch"
|
|
||||||
case "${{ github.ref }}" in
|
|
||||||
*trading)
|
|
||||||
echo ">> Only trading will be deployed"
|
|
||||||
projects_array=(trading)
|
|
||||||
projects_e2e_array=(trading)
|
|
||||||
;;
|
|
||||||
*governance)
|
|
||||||
echo ">> Only governance will be deployed"
|
|
||||||
projects_array=(governance)
|
|
||||||
projects_e2e_array=(governance)
|
|
||||||
;;
|
|
||||||
*explorer)
|
|
||||||
echo ">> Only explorer will be deployed"
|
|
||||||
projects_array=(explorer)
|
|
||||||
projects_e2e_array=(explorer)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo ">> All apps will be deployed"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
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
|
|
||||||
|
|
||||||
|
- name: Build affected
|
||||||
|
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
||||||
outputs:
|
outputs:
|
||||||
projects: ${{ env.PROJECTS }}
|
projects: ${{ env.PROJECTS }}
|
||||||
projects-e2e: ${{ env.PROJECTS_E2E }}
|
projects-e2e: ${{ env.PROJECTS_E2E }}
|
||||||
@@ -224,30 +170,62 @@ jobs:
|
|||||||
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
||||||
preview_tools: ${{ env.PREVIEW_TOOLS }}
|
preview_tools: ${{ env.PREVIEW_TOOLS }}
|
||||||
|
|
||||||
|
check-e2e-needed:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build-sources
|
||||||
|
name: '(CI) check if e2e needed'
|
||||||
|
outputs:
|
||||||
|
run-tests: ${{ steps.check-test.outputs.e2e-needed }}
|
||||||
|
steps:
|
||||||
|
- name: Check branch
|
||||||
|
id: check-test
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.base_ref }}" == "develop" ]]; then
|
||||||
|
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${{ github.base_ref }}" == "main" ]]; then
|
||||||
|
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/"* ]]; then
|
||||||
|
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "e2e-needed=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
- name: Print result
|
||||||
|
run: |
|
||||||
|
echo "e2e-needed: ${{ steps.check-test.outputs.e2e-needed }}"
|
||||||
|
|
||||||
cypress:
|
cypress:
|
||||||
needs: lint-test-build
|
needs: [build-sources, check-e2e-needed]
|
||||||
name: '(CI) cypress'
|
name: '(CI) cypress'
|
||||||
# if: ${{ needs.lint-test-build.outputs.projects-e2e != '[]' }}
|
if: ${{ needs.check-e2e-needed.outputs.run-tests == 'true' }}
|
||||||
uses: ./.github/workflows/cypress-run.yml
|
uses: ./.github/workflows/cypress-run.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
|
projects: ${{ needs.build-sources.outputs.projects-e2e }}
|
||||||
tags: '@smoke @regression'
|
tags: '@smoke'
|
||||||
|
|
||||||
|
console-e2e:
|
||||||
|
needs: [build-sources, check-e2e-needed]
|
||||||
|
name: '(CI) console python'
|
||||||
|
uses: ./.github/workflows/console-test-run.yml
|
||||||
|
secrets: inherit
|
||||||
|
if: needs.check-e2e-needed.outputs.run-tests == 'true' && contains(needs.build-sources.outputs.projects, 'trading')
|
||||||
|
with:
|
||||||
|
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
publish-dist:
|
publish-dist:
|
||||||
needs: lint-test-build
|
needs: build-sources
|
||||||
name: '(CD) publish dist'
|
name: '(CD) publish dist'
|
||||||
if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo') || github.event_name == 'push' }}
|
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
|
uses: ./.github/workflows/publish-dist.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
projects: ${{ needs.lint-test-build.outputs.projects }}
|
projects: ${{ needs.build-sources.outputs.projects }}
|
||||||
|
|
||||||
dist-check:
|
dist-check:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
- publish-dist
|
- publish-dist
|
||||||
- lint-test-build
|
- build-sources
|
||||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }}
|
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }}
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
name: '(CD) comment preview links'
|
name: '(CD) comment preview links'
|
||||||
@@ -263,27 +241,27 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url
|
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url
|
||||||
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
|
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_governance }}" =~ $regex ]]; then
|
if [[ "${{ needs.build-sources.outputs.preview_governance }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do
|
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_governance }}"; do
|
||||||
echo "waiting for governance preview: ${{ needs.lint-test-build.outputs.preview_governance }}"
|
echo "waiting for governance preview: ${{ needs.build-sources.outputs.preview_governance }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_explorer }}" =~ $regex ]]; then
|
if [[ "${{ needs.build-sources.outputs.preview_explorer }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do
|
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_explorer }}"; do
|
||||||
echo "waiting for explorer preview: ${{ needs.lint-test-build.outputs.preview_explorer }}"
|
echo "waiting for explorer preview: ${{ needs.build-sources.outputs.preview_explorer }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_trading }}" =~ $regex ]]; then
|
if [[ "${{ needs.build-sources.outputs.preview_trading }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do
|
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_trading }}"; do
|
||||||
echo "waiting for trading preview: ${{ needs.lint-test-build.outputs.preview_trading }}"
|
echo "waiting for trading preview: ${{ needs.build-sources.outputs.preview_trading }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_tools }}" =~ $regex ]]; then
|
if [[ "${{ needs.build-sources.outputs.preview_tools }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do
|
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_tools }}"; do
|
||||||
echo "waiting for tools preview: ${{ needs.lint-test-build.outputs.preview_tools }}"
|
echo "waiting for tools preview: ${{ needs.build-sources.outputs.preview_tools }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
@@ -295,10 +273,10 @@ jobs:
|
|||||||
issue-number: ${{ github.event.pull_request.number }}
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
body: |
|
body: |
|
||||||
Previews
|
Previews
|
||||||
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
|
* governance: ${{ needs.build-sources.outputs.preview_governance }}
|
||||||
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
|
* explorer: ${{ needs.build-sources.outputs.preview_explorer }}
|
||||||
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
|
* trading: ${{ needs.build-sources.outputs.preview_trading }}
|
||||||
* tools: ${{ needs.lint-test-build.outputs.preview_tools }}
|
* tools: ${{ needs.build-sources.outputs.preview_tools }}
|
||||||
|
|
||||||
# Report single result at the end, to avoid mess with required checks in PR
|
# Report single result at the end, to avoid mess with required checks in PR
|
||||||
cypress-check:
|
cypress-check:
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#managing-caches
|
||||||
|
name: cleanup caches by a branch
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- closed
|
||||||
|
jobs:
|
||||||
|
cleanup:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Cleanup
|
||||||
|
run: |
|
||||||
|
gh extension install actions/gh-actions-cache
|
||||||
|
|
||||||
|
echo "Fetching list of cache key"
|
||||||
|
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
|
||||||
|
|
||||||
|
## Setting this to not fail the workflow while deleting cache keys.
|
||||||
|
set +e
|
||||||
|
echo "Deleting caches..."
|
||||||
|
for cacheKey in $cacheKeysForPR
|
||||||
|
do
|
||||||
|
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
|
||||||
|
done
|
||||||
|
echo "Done"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
|
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||||
@@ -1,55 +1,218 @@
|
|||||||
name: console-test-run
|
name: (CI) Console tests
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
github-sha:
|
github-sha:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
console-test-branch:
|
||||||
|
type: choice
|
||||||
|
description: 'main: v0.72.14, develop: v0.73.0-preview7'
|
||||||
|
options:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
console-test:
|
create-docker-image:
|
||||||
timeout-minutes: 5
|
name: Create docker image for console-test
|
||||||
runs-on: self-hosted-runner
|
runs-on: ubuntu-22.04
|
||||||
|
timeout-minutes: 20
|
||||||
steps:
|
steps:
|
||||||
|
#----------------------------------------------
|
||||||
|
# check-out frontend-monorepo
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Checkout frontend-monorepo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.github-sha || github.sha }}
|
||||||
|
#----------------------------------------------
|
||||||
|
# cache node modules
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: setup node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '16'
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
|
- 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-
|
||||||
|
#----------------------------------------------
|
||||||
|
# install deps if cache missing
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: yarn install
|
||||||
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
|
run: yarn install --pure-lockfile
|
||||||
|
#----------------------------------------------
|
||||||
|
# build trading
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Build trading app
|
||||||
|
run: |
|
||||||
|
yarn env-cmd -f ./apps/trading/.env.stagnet1 yarn nx export trading
|
||||||
|
DIST_LOCATION=dist/apps/trading/exported
|
||||||
|
mv $DIST_LOCATION dist-result
|
||||||
|
tree dist-result
|
||||||
|
|
||||||
|
#----------------------------------------------
|
||||||
|
# export trading app docker image
|
||||||
|
#----------------------------------------------
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Build and export to local Docker
|
||||||
|
id: docker_build
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: docker/node-outside-docker.Dockerfile
|
||||||
|
load: true
|
||||||
|
build-args: |
|
||||||
|
APP=trading
|
||||||
|
ENV_NAME=stagnet1
|
||||||
|
tags: ci/trading:local
|
||||||
|
outputs: type=docker,dest=/tmp/console-image.tar
|
||||||
|
|
||||||
|
- name: Verify docker image created
|
||||||
|
run: |
|
||||||
|
echo ${{ steps.docker_build.outputs.digest }}
|
||||||
|
echo ${{ steps.docker_build.outputs.imageid }}
|
||||||
|
|
||||||
|
- name: Upload docker image for console-test usage
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: console-image
|
||||||
|
path: /tmp/console-image.tar
|
||||||
|
|
||||||
|
console-test-branch:
|
||||||
|
name: Choose console-test branch to run on
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
timeout-minutes: 5
|
||||||
|
outputs:
|
||||||
|
console-branch: ${{ steps.output-step.outputs.branch }}
|
||||||
|
steps:
|
||||||
|
- name: Workflow dispatch input
|
||||||
|
id: dispatch-step
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
|
run: echo "branch=${{ inputs.console-test-branch }}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Print Workflow dispatch input
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
|
run: echo ${{ steps.dispatch-step.outputs.branch }}
|
||||||
|
|
||||||
|
- name: Workflow_call input
|
||||||
|
id: workflow_call-step
|
||||||
|
if: github.event_name != 'workflow_dispatch'
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.base_ref }}" == "main" ]]; then
|
||||||
|
echo "branch=main" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${{ github.base_ref }}" == "develop" && "${{ github.ref_name }}" == "main" ]]; then
|
||||||
|
echo "branch=main" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/mainnet"* ]]; then
|
||||||
|
echo "branch=main" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "branch=develop" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Print Workflow_call input
|
||||||
|
if: github.event_name != 'workflow_dispatch'
|
||||||
|
run: echo ${{ steps.workflow_call-step.outputs.branch }}
|
||||||
|
|
||||||
|
- name: Set output
|
||||||
|
id: output-step
|
||||||
|
run: echo "branch=${{ steps.dispatch-step.outputs.branch || steps.workflow_call-step.outputs.branch }}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Print final output
|
||||||
|
run: echo ${{ steps.output-step.outputs.branch }}
|
||||||
|
|
||||||
|
run-tests:
|
||||||
|
name: run-tests
|
||||||
|
runs-on: 8-cores
|
||||||
|
needs: [create-docker-image, console-test-branch]
|
||||||
|
timeout-minutes: 20
|
||||||
|
steps:
|
||||||
|
#----------------------------------------------
|
||||||
|
# load docker image
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Download docker image from previous job
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: console-image
|
||||||
|
path: /tmp
|
||||||
|
|
||||||
|
- name: Load Docker image
|
||||||
|
run: |
|
||||||
|
docker load --input /tmp/console-image.tar
|
||||||
|
docker image ls -a
|
||||||
|
|
||||||
|
#----------------------------------------------
|
||||||
|
# check-out tests repo
|
||||||
|
#----------------------------------------------
|
||||||
- name: Checkout console test repo
|
- name: Checkout console test repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: vegaprotocol/console-test
|
repository: vegaprotocol/console-test
|
||||||
path: './console-test'
|
ref: ${{ needs.console-test-branch.outputs.console-branch }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Load console test envs
|
||||||
|
id: console-test-env
|
||||||
|
uses: falti/dotenv-action@v1.0.4
|
||||||
|
with:
|
||||||
|
path: '.env.${{ needs.console-test-branch.outputs.console-branch }}'
|
||||||
|
export-variables: true
|
||||||
|
keys-case: upper
|
||||||
|
log-variables: true
|
||||||
|
|
||||||
|
#----------------------------------------------
|
||||||
|
# ----- Setup python -----
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.10.11'
|
python-version: '3.10'
|
||||||
|
#----------------------------------------------
|
||||||
|
# ----- install & configure poetry -----
|
||||||
|
#----------------------------------------------
|
||||||
- name: Install Poetry
|
- name: Install Poetry
|
||||||
uses: snok/install-poetry@v1
|
uses: snok/install-poetry@v1
|
||||||
|
with:
|
||||||
|
virtualenvs-create: true
|
||||||
|
virtualenvs-in-project: true
|
||||||
|
virtualenvs-path: .venv
|
||||||
|
|
||||||
|
#----------------------------------------------
|
||||||
|
# install python dependencies
|
||||||
|
#----------------------------------------------
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: poetry install --no-interaction --no-root
|
||||||
poetry install --no-root
|
#----------------------------------------------
|
||||||
working-directory: ./console-test
|
# install vega binaries
|
||||||
|
#----------------------------------------------
|
||||||
- name: load Binaries
|
- name: Install vega binaries
|
||||||
run: |
|
run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
|
||||||
poetry run python -m vega_sim.tools.load_binaries
|
#----------------------------------------------
|
||||||
working-directory: ./console-test
|
# install playwright
|
||||||
|
#----------------------------------------------
|
||||||
- name: pull console
|
|
||||||
run: |
|
|
||||||
poetry run docker pull ghcr.io/vegaprotocol/frontend/trading:${{ inputs.github-sha }}
|
|
||||||
|
|
||||||
- name: Update container_name in config.py
|
|
||||||
run: |
|
|
||||||
sed -i "s/container_name = \".*\"/container_name = \"vegaprotocol\/frontend\/trading:${{ inputs.github-sha }}\"/g" config.py
|
|
||||||
|
|
||||||
- name: install playwright
|
- name: install playwright
|
||||||
run: poetry run playwright install
|
run: poetry run playwright install --with-deps chromium
|
||||||
working-directory: ./console-test
|
#----------------------------------------------
|
||||||
|
# run tests
|
||||||
- name: run tests
|
#----------------------------------------------
|
||||||
run: poetry run pytest --numprocesses auto
|
- name: Run tests
|
||||||
working-directory: ./console-test
|
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
|
||||||
|
|
||||||
|
#----------------------------------------------
|
||||||
|
# upload traces
|
||||||
|
#----------------------------------------------
|
||||||
- name: Upload Playwright Trace
|
- name: Upload Playwright Trace
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
if: always()
|
if: always()
|
||||||
@@ -57,3 +220,13 @@ jobs:
|
|||||||
name: playwright-trace
|
name: playwright-trace
|
||||||
path: ./traces/
|
path: ./traces/
|
||||||
retention-days: 15
|
retention-days: 15
|
||||||
|
#----------------------------------------------
|
||||||
|
# ----- upload logs -----
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Upload worker logs
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: worker-logs
|
||||||
|
path: ./logs/
|
||||||
|
retention-days: 15
|
||||||
|
|||||||
@@ -13,14 +13,36 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
runner-choice:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
runner: ${{ steps.step.outputs.runner }}
|
||||||
|
steps:
|
||||||
|
- name: Check branch
|
||||||
|
id: step
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.base_ref }}" == "main" ]]; then
|
||||||
|
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${{ github.base_ref }}" == "develop" && "${{ github.ref_name }}" == "main" ]]; then
|
||||||
|
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/mainnet"* ]]; then
|
||||||
|
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "runner=self-hosted-runner" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Print runner
|
||||||
|
run: echo ${{ steps.step.outputs.runner }}
|
||||||
|
|
||||||
e2e:
|
e2e:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
project: ${{ fromJSON(inputs.projects) }}
|
project: ${{ fromJSON(inputs.projects) }}
|
||||||
name: ${{ matrix.project }}
|
name: ${{ matrix.project }}
|
||||||
runs-on: self-hosted-runner
|
needs: runner-choice
|
||||||
timeout-minutes: 100
|
runs-on: ${{ needs.runner-choice.outputs.runner }}
|
||||||
|
timeout-minutes: 120
|
||||||
steps:
|
steps:
|
||||||
# Checks if skip cache was requested
|
# Checks if skip cache was requested
|
||||||
- name: Set skip-nx-cache flag
|
- name: Set skip-nx-cache flag
|
||||||
@@ -37,6 +59,7 @@ jobs:
|
|||||||
|
|
||||||
# Restore node_modules from cache if possible
|
# Restore node_modules from cache if possible
|
||||||
- name: Restore node_modules from cache
|
- name: Restore node_modules from cache
|
||||||
|
id: cache-node-modules
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
@@ -46,6 +69,7 @@ jobs:
|
|||||||
|
|
||||||
# Install frontend dependencies
|
# Install frontend dependencies
|
||||||
- name: Install root dependencies
|
- name: Install root dependencies
|
||||||
|
if: steps.cache-node-modules.outputs.cache-hit != 'true'
|
||||||
run: yarn install --frozen-lockfile
|
run: yarn install --frozen-lockfile
|
||||||
working-directory: frontend-monorepo
|
working-directory: frontend-monorepo
|
||||||
|
|
||||||
@@ -61,13 +85,14 @@ jobs:
|
|||||||
- name: Run Vegacapsule network and Vega wallet
|
- name: Run Vegacapsule network and Vega wallet
|
||||||
id: setup-vega
|
id: setup-vega
|
||||||
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
|
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
|
||||||
|
timeout-minutes: 10
|
||||||
|
|
||||||
######
|
######
|
||||||
## Run some tests
|
## Run some tests
|
||||||
######
|
######
|
||||||
|
|
||||||
- name: Run Cypress tests
|
- name: Run Cypress tests
|
||||||
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --browser chrome --env.grepTags="${{ inputs.tags }}"
|
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --browser chrome --env.grepTags="${{ inputs.tags }}"
|
||||||
working-directory: frontend-monorepo
|
working-directory: frontend-monorepo
|
||||||
env:
|
env:
|
||||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||||
|
|||||||
@@ -2,7 +2,12 @@
|
|||||||
name: Verify PR title
|
name: Verify PR title
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
pull_request:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- edited
|
||||||
|
- reopened
|
||||||
|
- synchronize
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint_pr:
|
lint_pr:
|
||||||
@@ -11,21 +16,16 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version: 16
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: Cache node modules
|
- name: Install dependencies
|
||||||
uses: actions/cache@v3
|
run: |
|
||||||
with:
|
rm package.json
|
||||||
path: node_modules
|
npm install --no-save @commitlint/cli @commitlint/config-conventional @commitlint/config-nx-scopes nx
|
||||||
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
|
||||||
|
|
||||||
- name: Check PR title
|
- name: Check PR title
|
||||||
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
||||||
|
|||||||
@@ -29,6 +29,18 @@ jobs:
|
|||||||
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
|
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
|
||||||
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
||||||
echo IS_S3_RELEASE=false >> $GITHUB_ENV
|
echo IS_S3_RELEASE=false >> $GITHUB_ENV
|
||||||
|
echo IS_DEV_IMAGE=false >> $GITHUB_ENV
|
||||||
|
echo IS_MAIN_IMAGE=false >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is dev image
|
||||||
|
if: ${{ github.ref_name == 'develop' && github.event_name == 'push' && matrix.app == 'trading' }}
|
||||||
|
run: |
|
||||||
|
echo IS_DEV_IMAGE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is main image
|
||||||
|
if: ${{ github.ref_name == 'main' && github.event_name == 'push' && matrix.app == 'trading' }}
|
||||||
|
run: |
|
||||||
|
echo IS_MAIN_IMAGE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Is PR
|
- name: Is PR
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
@@ -36,7 +48,7 @@ jobs:
|
|||||||
echo IS_PR=true >> $GITHUB_ENV
|
echo IS_PR=true >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Is mainnet release
|
- name: Is mainnet release
|
||||||
if: ${{ contains(github.ref, 'release/mainnnet') && !contains(github.ref, 'mirror') }}
|
if: ${{ contains(github.ref, 'release/mainnet') && !contains(github.ref, 'mirror') }}
|
||||||
run: |
|
run: |
|
||||||
echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV
|
echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
@@ -51,7 +63,7 @@ jobs:
|
|||||||
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Is S3 Release
|
- name: Is S3 Release
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' && github.ref_name != 'main'}}
|
||||||
run: |
|
run: |
|
||||||
echo IS_S3_RELEASE=true >> $GITHUB_ENV
|
echo IS_S3_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
@@ -75,7 +87,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Log in to the Container registry (docker hub)
|
- name: Log in to the Container registry (docker hub)
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == 'true' }}
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
@@ -97,52 +109,13 @@ jobs:
|
|||||||
- name: Define dist variables
|
- name: Define dist variables
|
||||||
if: ${{ github.event_name == 'push' }}
|
if: ${{ github.event_name == 'push' }}
|
||||||
run: |
|
run: |
|
||||||
envName=''
|
python3 tools/ci/define-dist-variables.py --github-ref="${{ github.ref }}" --app="${{ matrix.app }}"
|
||||||
domain="vega.rocks"
|
|
||||||
bucketName=''
|
|
||||||
|
|
||||||
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
|
- name: Verify script result
|
||||||
# remove prefixing release/ and take the first string limited by - which is supposed to be name of the environment for releasing (format: release/testnet-trading)
|
if: ${{ github.event_name == 'push' }}
|
||||||
envName="$(echo ${{ github.ref }} | sed -e "s|refs/heads/release/||" | cut -d '-' -f 1 )"
|
run: |
|
||||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
echo "BUCKET_NAME=${{ env.BUCKET_NAME }}"
|
||||||
envName="stagnet1"
|
echo "ENV_NAME=${{ env.ENV_NAME }}"
|
||||||
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 }}" =~ .*mainnet$ ]]; 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: Build local dist
|
- name: Build local dist
|
||||||
run: |
|
run: |
|
||||||
@@ -157,8 +130,12 @@ jobs:
|
|||||||
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
||||||
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
||||||
DIST_LOCATION=dist/storybook/ui-toolkit
|
DIST_LOCATION=dist/storybook/ui-toolkit
|
||||||
|
elif [ "${{ matrix.app }}" = "static" ]; then
|
||||||
|
yarn nx build static || (yarn install && yarn nx build static)
|
||||||
else
|
else
|
||||||
$envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }})
|
$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 }}
|
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
||||||
fi
|
fi
|
||||||
mv $DIST_LOCATION dist-result
|
mv $DIST_LOCATION dist-result
|
||||||
@@ -184,10 +161,10 @@ jobs:
|
|||||||
- name: Sanity check docker image
|
- name: Sanity check docker image
|
||||||
run: |
|
run: |
|
||||||
echo "Check ipfs-hash"
|
echo "Check ipfs-hash"
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash'
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash > ${{ matrix.app }}-ipfs-hash
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash' > ${{ matrix.app }}-ipfs-hash
|
||||||
echo "List html directory"
|
echo "List html directory"
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree /usr/share/nginx/html'
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'apk add --update tree; tree /usr/share/nginx/html'
|
||||||
|
|
||||||
- name: Publish dist as docker image (ghcr)
|
- name: Publish dist as docker image (ghcr)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
@@ -208,7 +185,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
id: dockerhub-push
|
id: dockerhub-push
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == 'true' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/node-outside-docker.Dockerfile
|
file: docker/node-outside-docker.Dockerfile
|
||||||
@@ -218,7 +195,7 @@ jobs:
|
|||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || env.IS_MAIN_IMAGE == 'true' && 'main' || '' }}
|
||||||
|
|
||||||
- name: Publish dist as docker image (ghcr - retry)
|
- name: Publish dist as docker image (ghcr - retry)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
@@ -245,7 +222,7 @@ jobs:
|
|||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || env.IS_MAIN_IMAGE == 'true' && 'main' || '' }}
|
||||||
|
|
||||||
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
||||||
- name: Publish dist to s3
|
- name: Publish dist to s3
|
||||||
@@ -358,7 +335,9 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# create commit
|
# create commit
|
||||||
commit_msg="Automated hash update from ${{ github.ref }}"
|
if ! git diff --cached --exit-code; then
|
||||||
git commit -m "$commit_msg"
|
commit_msg="Automated hash update from ${{ github.ref }}"
|
||||||
git push -u origin "main"
|
git commit -m "$commit_msg"
|
||||||
|
git push -u origin "main"
|
||||||
|
fi
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ on:
|
|||||||
- types
|
- types
|
||||||
- utils
|
- utils
|
||||||
- i18n
|
- i18n
|
||||||
|
- wallet
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
|
|||||||
@@ -3,6 +3,3 @@
|
|||||||
|
|
||||||
# Lint commit messages to ensure they follow conventional commit standards
|
# Lint commit messages to ensure they follow conventional commit standards
|
||||||
yarn commitlint --edit "${1}"
|
yarn commitlint --edit "${1}"
|
||||||
|
|
||||||
# Lint all staged files
|
|
||||||
yarn lint-staged
|
|
||||||
|
|||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
# Lint all staged files
|
||||||
|
yarn lint-staged
|
||||||
Executable
+8
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
# Lint all staged files
|
||||||
|
yarn nx format:check
|
||||||
|
|
||||||
|
# Test all projects with changes
|
||||||
|
yarn nx affected -t test --exclude trading
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
* @vegaprotocol/frontend
|
* @vegaprotocol/frontend
|
||||||
|
* @vegaprotocol/frontend-qa
|
||||||
*.graphql @vegaprotocol/core
|
*.graphql @vegaprotocol/core
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ recalculate-ipfs:
|
|||||||
echo "ipfs hash inside the image"
|
echo "ipfs hash inside the image"
|
||||||
docker run --rm ${TAG} cat /ipfs-hash
|
docker run --rm ${TAG} cat /ipfs-hash
|
||||||
echo "recalculating ipfs hash"
|
echo "recalculating ipfs hash"
|
||||||
docker run --rm ${TAG} ipfs add -r /usr/share/nginx/html
|
docker run --rm ${TAG} ipfs add -rQ /usr/share/nginx/html
|
||||||
|
|
||||||
.PHONY: eject-ipfs-hash
|
.PHONY: eject-ipfs-hash
|
||||||
unpack:
|
unpack:
|
||||||
|
|||||||
@@ -113,13 +113,47 @@ In order to run a container on port 3000:
|
|||||||
docker run -p 3000:80 [TAG]
|
docker run -p 3000:80 [TAG]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
On top of that there are two possible scenarios for running docker image - using nginx server (default) of ipfs daemon.
|
||||||
|
|
||||||
|
to run ipfs on port 3000:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -p 3000:80 [TAG] /run-ipfs.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
to run nginx on port 3000:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -p 3000:80 [TAG]
|
||||||
|
```
|
||||||
|
|
||||||
## Build instructions
|
## Build instructions
|
||||||
|
|
||||||
The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of console either for the web, or ready for pinning on IPFS
|
The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of Console either for the web, or ready for pinning on IPFS.
|
||||||
|
|
||||||
|
### nx build inside the docker
|
||||||
|
|
||||||
|
Using multistage dockerfile dist is compiled using [node](https://hub.docker.com/_/node) image and later packed to nginx as in [dist build](#dist-build). The multistage builds ensures consistent CPU architecture and build toolchains are used so that the result will be identical.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=16.5.1 --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Computing ipfs-hash of the build
|
||||||
|
|
||||||
|
At the moment this feature is important only for Console releases.
|
||||||
|
|
||||||
|
Each docker build finishes with hash calculation for ` dist`` directory. Resulting hash is added to file named as `/ipfs-hash`. Once docker image is produced you can run following commad to display ipfs-hash:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make recalculate-ipfs TAG=vegaprotocol/trading:{YOUR_VERSION}
|
||||||
|
```
|
||||||
|
|
||||||
|
**updating hash:** recompiling dist directory (even if there are no changed to source code) results in different hash computed by ipfs command.
|
||||||
|
|
||||||
### nx build outside the docker
|
### nx build outside the docker
|
||||||
|
|
||||||
Packaging prepared dist into [`nginx`](https://hub.docker.com/_/nginx)([server configuration](./nginx/nginx.conf)) docker image involves building the application on docker host machine from source.
|
This Docker image packages a pre-built `dist` folder into an [`nginx`](https://hub.docker.com/_/nginx)([server configuration](./nginx/nginx.conf)) docker image. In this case, the application on docker host machine from source.
|
||||||
|
|
||||||
As a prerequisite you need to perform build of `dist` directory and move its content for specific application to `dist-result` directory. Use following script to do it with a single command:
|
As a prerequisite you need to perform build of `dist` directory and move its content for specific application to `dist-result` directory. Use following script to do it with a single command:
|
||||||
|
|
||||||
@@ -130,41 +164,21 @@ As a prerequisite you need to perform build of `dist` directory and move its con
|
|||||||
You can build any of the containers locally with the following command:
|
You can build any of the containers locally with the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build --dockerfile docker/node-outside-docker.Dockerfile . --tag=[TAG]
|
docker build -f docker/node-outside-docker.Dockerfile . --tag=[TAG]
|
||||||
```
|
```
|
||||||
|
|
||||||
### nx build inside the docker
|
|
||||||
|
|
||||||
Using multistage dockerfile dist is compiled using [node](https://hub.docker.com/_/node) image and later packed to nginx as in [dist build](#dist-build) example.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=$(cat .nvmrc) --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
|
|
||||||
```
|
|
||||||
|
|
||||||
### Computing ipfs-hash of the build
|
|
||||||
|
|
||||||
At the moment this feature is important only for `trading` (console) releases.
|
|
||||||
|
|
||||||
Each docker build finishes with hash calculation for dist directory. Resulting hash is added to file named as `/ipfs-hash`. Once docker image is produced you can run following commad to display ipfs-hash:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make recalculate-ipfs TAG=vegaprotocol/trading:{YOUR_VERSION}
|
|
||||||
```
|
|
||||||
|
|
||||||
**updating hash:** recompiling dist directory (even if there are no changed to source code) results in different hash computed by ipfs command.
|
|
||||||
|
|
||||||
### Verifying ipfs-hash of existing current application version
|
### Verifying ipfs-hash of existing current application version
|
||||||
|
|
||||||
An IPFS CID will be attached to every [release](https://github.com/vegaprotocol/frontend-monorepo/releases). If you are intending to pin an application on IPFS, you can check that your build matches by running the following steps:
|
An IPFS CID will be attached to every [release](https://github.com/vegaprotocol/frontend-monorepo/releases). If you are intending to pin an application on IPFS, you can check that your build matches by running the following steps:
|
||||||
|
|
||||||
1. Show latest release by runnning: `make latest-release`. You need to configure [`gh`](https://cli.github.com/) for this step to work, otherwise please provide release manually from [github](https://github.com/vegaprotocol/frontend-monorepo/releases) or [dockerhub](https://hub.docker.com/r/vegaprotocol/trading)
|
1. Show latest release by running: `make latest-release`. You need to configure [`gh`](https://cli.github.com/) for this step to work, otherwise please provide release manually from [github](https://github.com/vegaprotocol/frontend-monorepo/releases) or [dockerhub](https://hub.docker.com/r/vegaprotocol/trading)
|
||||||
2. Set RELEASE environment variable to value that you want to validate: `export RELEASE=$(make latest-release)` or `export RELEASE=vXX.XX.XX`
|
2. Set RELEASE environment variable to value that you want to validate: `export RELEASE=$(make latest-release)` or `export RELEASE=vXX.XX.XX`
|
||||||
3. Set TAG environment variable to image that you want to validate: `export TAG=vegaprotocol/trading:$RELEASE`
|
3. Set TAG environment variable to image that you want to validate: `export TAG=vegaprotocol/trading:$RELEASE`
|
||||||
4. Download docker image with the desired release `docker pull $TAG`.
|
4. Download docker image with the desired release `docker pull $TAG`.
|
||||||
5. Recalculate hash: `make recalculate-ipfs`
|
5. Recalculate hash: `make recalculate-ipfs`
|
||||||
6. You should see exactly same hash produced by ipfs command as one placed with the release notes: `make show-latest-release`
|
6. You should see exactly same hash produced by ipfs command as one placed with the release notes: `make show-latest-release`
|
||||||
7. If you want to extract dist from docker image to your local filesystem you can run following command: `make unpack`
|
7. If you want to extract dist from docker image to your local filesystem you can run following command: `make unpack`
|
||||||
8. Now `dist` directory contains valid application build. **it is not possible to calculate same ipfs hash on files that are result of copy operation**
|
8. Now `dist` directory contains valid application build
|
||||||
|
|
||||||
## Config
|
## Config
|
||||||
|
|
||||||
|
|||||||
@@ -16,5 +16,10 @@ NX_EXPLORER_NETWORK_PARAMETERS=1
|
|||||||
NX_EXPLORER_PARTIES=1
|
NX_EXPLORER_PARTIES=1
|
||||||
NX_EXPLORER_VALIDATORS=1
|
NX_EXPLORER_VALIDATORS=1
|
||||||
|
|
||||||
CYPRESS_VEGA_WALLET_API_TOKEN=
|
|
||||||
CYPRESS_VEGA_URL=http://localhost:3008/graphql
|
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,6 +4,8 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket
|
|||||||
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
||||||
NX_VEGA_ENV=DEVNET
|
NX_VEGA_ENV=DEVNET
|
||||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocke
|
|||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
NX_VEGA_ENV=MAINNET
|
NX_VEGA_ENV=MAINNET
|
||||||
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
|
|||||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||||
NX_VEGA_ENV=TESTNET
|
NX_VEGA_ENV=TESTNET
|
||||||
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ module.exports = defineConfig({
|
|||||||
viewportWidth: 1440,
|
viewportWidth: 1440,
|
||||||
viewportHeight: 900,
|
viewportHeight: 900,
|
||||||
testIsolation: false,
|
testIsolation: false,
|
||||||
|
experimentalMemoryManagement: true,
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
environment: 'CUSTOM',
|
environment: 'CUSTOM',
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"proposalSubmission": {
|
||||||
|
"rationale": {
|
||||||
|
"title": "Test new asset proposal",
|
||||||
|
"description": "E2E test for proposals"
|
||||||
|
},
|
||||||
|
"terms": {
|
||||||
|
"newAsset": {
|
||||||
|
"changes": {
|
||||||
|
"name": "USDT Coin",
|
||||||
|
"symbol": "USDT",
|
||||||
|
"decimals": "18",
|
||||||
|
"quantum": "1",
|
||||||
|
"erc20": {
|
||||||
|
"contractAddress": "0xb404c51bbc10dcbe948077f18a4b8e553d160084",
|
||||||
|
"withdrawThreshold": "10",
|
||||||
|
"lifetimeLimit": "10"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"closingTimestamp": 1724339572,
|
||||||
|
"enactmentTimestamp": 1724339572,
|
||||||
|
"validationTimestamp": 1692799617
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,169 @@
|
|||||||
//Tests set to skip until market bug for capsule checkpoint is fixed
|
import { createSuccessorMarketProposal } from '../support/governance.functions';
|
||||||
context.skip('Market page', { tags: '@regression' }, function () {
|
|
||||||
describe('Verify elements on page', function () {
|
|
||||||
const marketHeaders = '[data-testid="markets-header"]';
|
|
||||||
const marketNavigation = 'a[href="/markets"]';
|
|
||||||
|
|
||||||
it('Markets page is displayed', function () {
|
context('Market page', { tags: '@regression' }, function () {
|
||||||
|
describe('Verify elements on page', function () {
|
||||||
|
const marketHeaders = 'markets-heading';
|
||||||
|
|
||||||
|
before('Create market', function () {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.get(marketNavigation).click();
|
cy.createMarket();
|
||||||
cy.common_validate_blocks_data_displayed(marketHeaders);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Markets page displayed on mobile', function () {
|
beforeEach('Get market id', function () {
|
||||||
|
cy.navigate_to('markets');
|
||||||
|
cy.get('[col-id="id"]').last().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.contains('Test market 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');
|
||||||
|
// Liquidity price range
|
||||||
|
cy.validate_element_from_table(
|
||||||
|
'Liquidity Price Range',
|
||||||
|
'95.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');
|
||||||
|
cy.getByTestId('icon-cross').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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.common_switch_to_mobile_and_click_toggle();
|
||||||
cy.get(marketNavigation).click();
|
cy.navigate_to('markets', true);
|
||||||
cy.common_validate_blocks_data_displayed(marketHeaders);
|
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 for successor market', function () {
|
||||||
|
const successionLineItem = 'succession-line-item';
|
||||||
|
const successionLineMarketId = 'succession-line-item-market-id';
|
||||||
|
|
||||||
|
createSuccessorMarketProposal(this.createdMarketId);
|
||||||
|
cy.navigate_to('markets');
|
||||||
|
cy.reload();
|
||||||
|
cy.contains('Token test market', { timeout: 8000 }).should('be.visible');
|
||||||
|
cy.get('[row-index="0"]')
|
||||||
|
.invoke('attr', 'row-id')
|
||||||
|
.as('successorMarketId');
|
||||||
|
cy.contains('Token test market').click();
|
||||||
|
cy.getByTestId(marketHeaders).should('have.text', 'Token test market');
|
||||||
|
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');
|
||||||
|
|
||||||
|
cy.getByTestId(successionLineItem)
|
||||||
|
.first()
|
||||||
|
.within(() => {
|
||||||
|
cy.contains('Test market 1');
|
||||||
|
cy.getByTestId(successionLineMarketId).should(
|
||||||
|
'have.text',
|
||||||
|
this.createdMarketId
|
||||||
|
);
|
||||||
|
});
|
||||||
|
cy.getByTestId(successionLineItem)
|
||||||
|
.eq(1)
|
||||||
|
.within(() => {
|
||||||
|
cy.contains('Token test market');
|
||||||
|
cy.getByTestId(successionLineMarketId).should(
|
||||||
|
'have.text',
|
||||||
|
this.successorMarketId
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
context('Network parameters page', { tags: '@smoke' }, function () {
|
context('Network parameters page', { tags: '@smoke' }, function () {
|
||||||
before('navigate to network parameter page', function () {
|
before('navigate to network parameter page', function () {
|
||||||
cy.fixture('net_parameter_format_lookup').as('networkParameterFormat');
|
cy.fixture('net_parameter_format_lookup').as('networkParameterFormat');
|
||||||
|
cy.visit('/network-parameters');
|
||||||
});
|
});
|
||||||
describe('Verify elements on page', function () {
|
describe('Verify elements on page', function () {
|
||||||
beforeEach(() => {
|
|
||||||
cy.visit('/network-parameters');
|
|
||||||
});
|
|
||||||
|
|
||||||
const networkParametersHeader = '[data-testid="network-param-header"]';
|
const networkParametersHeader = '[data-testid="network-param-header"]';
|
||||||
const tableRows = '[data-testid="key-value-table-row"]';
|
const tableRows = '[data-testid="key-value-table-row"]';
|
||||||
|
|
||||||
@@ -16,6 +13,7 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
|||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 0006-NETW-021
|
||||||
it('should list each of the network parameters available', function () {
|
it('should list each of the network parameters available', function () {
|
||||||
cy.get_network_parameters().then((network_parameters) => {
|
cy.get_network_parameters().then((network_parameters) => {
|
||||||
const numberOfNetworkParametersInSystem =
|
const numberOfNetworkParametersInSystem =
|
||||||
@@ -198,6 +196,19 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 0006-NETW-022 0006-NETW-023
|
||||||
|
it('governance assets should be correctly grouped', function () {
|
||||||
|
cy.getByTestId('governance')
|
||||||
|
.should('exist')
|
||||||
|
.parent()
|
||||||
|
.should('have.attr', 'href', '/network-parameters#governance');
|
||||||
|
cy.get('[id="governance-proposal-asset"]')
|
||||||
|
.parent()
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId('key-value-table-row').should('have.length', 8);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should be able to see network parameters - on mobile', function () {
|
it('should be able to see network parameters - on mobile', function () {
|
||||||
cy.switchToMobile();
|
cy.switchToMobile();
|
||||||
cy.get_network_parameters().then((network_parameters) => {
|
cy.get_network_parameters().then((network_parameters) => {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ context.skip('Node switcher', { tags: '@regression' }, function () {
|
|||||||
const errorTypeTxt = 'Error: invalid url';
|
const errorTypeTxt = 'Error: invalid url';
|
||||||
const nodeErrorTxt = 'fakeUrl is not a valid url.';
|
const nodeErrorTxt = 'fakeUrl is not a valid url.';
|
||||||
|
|
||||||
cy.getByTestId('node-url-custom').click();
|
cy.getByTestId('node-url-custom').click({ force: true });
|
||||||
|
|
||||||
cy.getByTestId(customNodeBtn).within(() => {
|
cy.getByTestId(customNodeBtn).within(() => {
|
||||||
cy.get('input').clear().type('fakeUrl');
|
cy.get('input').clear().type('fakeUrl');
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
context('Oracle page', { tags: '@smoke' }, () => {
|
||||||
|
describe('Verify elements on page', () => {
|
||||||
|
before('create market and navigate to oracle page', () => {
|
||||||
|
cy.createMarket();
|
||||||
|
cy.visit('/oracles');
|
||||||
|
});
|
||||||
|
it('should see oracle data', () => {
|
||||||
|
cy.getByTestId('oracle-details').should('have.length.at.least', 2);
|
||||||
|
cy.getByTestId('oracle-details')
|
||||||
|
.should('exist')
|
||||||
|
.eq(0)
|
||||||
|
.within(() => {
|
||||||
|
cy.get('tr')
|
||||||
|
.eq(0)
|
||||||
|
.within(() => {
|
||||||
|
cy.get('th').should('have.text', 'ID');
|
||||||
|
cy.get('a').invoke('text').should('have.length', 64);
|
||||||
|
cy.get('a')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', '/oracles/');
|
||||||
|
});
|
||||||
|
cy.get('tr')
|
||||||
|
.eq(1)
|
||||||
|
.within(() => {
|
||||||
|
cy.get('th').should('have.text', 'Type');
|
||||||
|
cy.get('td').should('have.text', 'External data');
|
||||||
|
});
|
||||||
|
cy.get('tr')
|
||||||
|
.eq(2)
|
||||||
|
.within(() => {
|
||||||
|
cy.get('th').should('have.text', 'Signer');
|
||||||
|
cy.getByTestId('keytype').should('have.text', 'Vega');
|
||||||
|
cy.get('a').invoke('text').should('have.length', 64);
|
||||||
|
cy.get('a')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', '/parties/');
|
||||||
|
});
|
||||||
|
cy.get('tr')
|
||||||
|
.eq(3)
|
||||||
|
.within(() => {
|
||||||
|
cy.get('th').should('have.text', 'Settlement for');
|
||||||
|
cy.get('a').invoke('text').should('have.length', 64);
|
||||||
|
cy.get('a')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', '/markets/');
|
||||||
|
});
|
||||||
|
cy.get('tr')
|
||||||
|
.eq(4)
|
||||||
|
.within(() => {
|
||||||
|
cy.get('th').should('have.text', 'Matched data');
|
||||||
|
cy.get('td').should('have.text', '❌');
|
||||||
|
});
|
||||||
|
cy.get('details')
|
||||||
|
.eq(0)
|
||||||
|
.within(() => {
|
||||||
|
cy.contains('Filter').click();
|
||||||
|
cy.get('.language-json').should('exist');
|
||||||
|
});
|
||||||
|
cy.get('details')
|
||||||
|
.eq(1)
|
||||||
|
.within(() => {
|
||||||
|
cy.contains('JSON').click();
|
||||||
|
cy.get('.language-json').should('exist');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { getNewAssetTxBody } from '../support/governance.functions';
|
||||||
|
|
||||||
|
context('Proposal page', { tags: '@smoke' }, function () {
|
||||||
|
describe('Verify elements on page', function () {
|
||||||
|
const proposalHeading = 'proposals-heading';
|
||||||
|
const dateTimeRegex =
|
||||||
|
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
|
||||||
|
|
||||||
|
before('Create market proposal', function () {
|
||||||
|
cy.visit('/');
|
||||||
|
cy.createMarket();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Able to view proposal', function () {
|
||||||
|
const proposalTitle = 'Add Lorem Ipsum market';
|
||||||
|
|
||||||
|
cy.navigate_to('governanceProposals');
|
||||||
|
cy.getByTestId(proposalHeading).should('be.visible');
|
||||||
|
cy.contains(proposalTitle)
|
||||||
|
.parent()
|
||||||
|
.parent()
|
||||||
|
.parent()
|
||||||
|
.within(() => {
|
||||||
|
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
||||||
|
cy.get_element_by_col_id('type').should('have.text', 'NewMarket');
|
||||||
|
cy.get_element_by_col_id('state').should('have.text', 'Enacted');
|
||||||
|
cy.getByTestId('vote-progress').should('be.visible');
|
||||||
|
cy.getByTestId('vote-progress-bar-for')
|
||||||
|
.invoke('attr', 'style')
|
||||||
|
.should('eq', 'width: 100%;');
|
||||||
|
cy.get('[col-id="cDate"]')
|
||||||
|
.invoke('text')
|
||||||
|
.should('match', dateTimeRegex);
|
||||||
|
cy.get('[col-id="eDate"]')
|
||||||
|
.invoke('text')
|
||||||
|
.should('match', dateTimeRegex);
|
||||||
|
cy.getByTestId('external-link')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contains', 'https://governance.fairground.wtf/proposals/');
|
||||||
|
cy.contains('View terms').should('exist').click();
|
||||||
|
});
|
||||||
|
cy.getByTestId('dialog-title').should('have.text', proposalTitle);
|
||||||
|
cy.get('.language-json').should('exist');
|
||||||
|
cy.getByTestId('icon-cross').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip('Proposal page displayed on mobile', function () {
|
||||||
|
const proposalTitle = 'Add Lorem Ipsum market';
|
||||||
|
|
||||||
|
cy.common_switch_to_mobile_and_click_toggle();
|
||||||
|
cy.navigate_to('governanceProposals', true);
|
||||||
|
cy.getByTestId(proposalHeading).should('be.visible');
|
||||||
|
cy.get('[row-index="0"]').within(() => {
|
||||||
|
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Able to view new asset proposal', function () {
|
||||||
|
const proposalTitle = 'Test new asset proposal';
|
||||||
|
const newAssetProposalBody = getNewAssetTxBody();
|
||||||
|
cy.VegaWalletSubmitProposal(newAssetProposalBody);
|
||||||
|
|
||||||
|
cy.visit('/');
|
||||||
|
cy.navigate_to('governanceProposals');
|
||||||
|
cy.contains(proposalTitle)
|
||||||
|
.parent()
|
||||||
|
.parent()
|
||||||
|
.parent()
|
||||||
|
.within(() => {
|
||||||
|
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
||||||
|
cy.get_element_by_col_id('type').should('have.text', 'NewAsset');
|
||||||
|
cy.get_element_by_col_id('state').should(
|
||||||
|
'have.text',
|
||||||
|
'Waiting for Node Vote'
|
||||||
|
);
|
||||||
|
cy.getByTestId('vote-progress').should('be.visible');
|
||||||
|
cy.getByTestId('vote-progress-bar-against')
|
||||||
|
.invoke('attr', 'style')
|
||||||
|
.should('eq', 'width: 100%;');
|
||||||
|
cy.get('[col-id="cDate"]')
|
||||||
|
.invoke('text')
|
||||||
|
.should('match', dateTimeRegex);
|
||||||
|
cy.get('[col-id="eDate"]')
|
||||||
|
.invoke('text')
|
||||||
|
.should('match', dateTimeRegex);
|
||||||
|
cy.getByTestId('external-link')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contains', 'https://governance.fairground.wtf/proposals/');
|
||||||
|
cy.contains('View terms').should('exist').click();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -7,7 +7,11 @@ context('Validator page', { tags: '@smoke' }, function () {
|
|||||||
it('should be able to see validator tiles', function () {
|
it('should be able to see validator tiles', function () {
|
||||||
cy.getNodes().then((nodes) => {
|
cy.getNodes().then((nodes) => {
|
||||||
nodes.forEach((node) => {
|
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 () {
|
Cypress.Commands.add('common_switch_to_mobile_and_click_toggle', function () {
|
||||||
cy.viewport('iphone-x');
|
cy.viewport('iphone-x');
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.get('[data-testid="open-menu"]').click();
|
cy.get('[data-testid="button-menu-drawer"]').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('monitor_clipboard', () => {
|
Cypress.Commands.add('monitor_clipboard', () => {
|
||||||
@@ -88,3 +88,49 @@ Cypress.Commands.add('convert_number_to_max_four_decimal', (number) => {
|
|||||||
maximumFractionDigits: 4,
|
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);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Cypress.Commands.add(
|
||||||
|
'validate_proposal_change_type',
|
||||||
|
(tableRowName, changeType) => {
|
||||||
|
cy.contains(tableRowName).siblings().should('have.text', changeType);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
import { addSeconds, millisecondsToSeconds } from 'date-fns';
|
||||||
|
|
||||||
|
export function createSuccessorMarketProposal(parentMarketId) {
|
||||||
|
cy.VegaWalletSubmitProposal(getSuccessorTxBody(parentMarketId));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSuccessorTxBody(parentMarketId) {
|
||||||
|
const MIN_CLOSE_SEC = 500;
|
||||||
|
const MIN_ENACT_SEC = 700;
|
||||||
|
|
||||||
|
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||||
|
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
||||||
|
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||||
|
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
||||||
|
|
||||||
|
return {
|
||||||
|
proposalSubmission: {
|
||||||
|
rationale: {
|
||||||
|
title: 'Test successor market proposal details',
|
||||||
|
description: 'E2E test for successor market',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
newMarket: {
|
||||||
|
changes: {
|
||||||
|
decimalPlaces: '5',
|
||||||
|
positionDecimalPlaces: '5',
|
||||||
|
linearSlippageFactor: '0.001',
|
||||||
|
quadraticSlippageFactor: '0',
|
||||||
|
instrument: {
|
||||||
|
name: 'Token test market',
|
||||||
|
code: 'TEST.24h',
|
||||||
|
future: {
|
||||||
|
settlementAsset:
|
||||||
|
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc',
|
||||||
|
quoteName: 'fUSDC',
|
||||||
|
dataSourceSpecForSettlementData: {
|
||||||
|
external: {
|
||||||
|
oracle: {
|
||||||
|
signers: [
|
||||||
|
{
|
||||||
|
pubKey: {
|
||||||
|
key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
key: {
|
||||||
|
name: 'prices.BTC.value',
|
||||||
|
type: 'TYPE_INTEGER',
|
||||||
|
numberDecimalPlaces: '0',
|
||||||
|
},
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
operator: 'OPERATOR_GREATER_THAN',
|
||||||
|
value: '0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dataSourceSpecForTradingTermination: {
|
||||||
|
external: {
|
||||||
|
oracle: {
|
||||||
|
signers: [
|
||||||
|
{
|
||||||
|
pubKey: {
|
||||||
|
key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
key: {
|
||||||
|
name: 'trading.terminated.ETH5',
|
||||||
|
type: 'TYPE_BOOLEAN',
|
||||||
|
},
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
operator: 'OPERATOR_EQUALS',
|
||||||
|
value: 'true',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dataSourceSpecBinding: {
|
||||||
|
settlementDataProperty: 'prices.BTC.value',
|
||||||
|
tradingTerminationProperty: 'trading.terminated.ETH5',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
metadata: [
|
||||||
|
'sector:food',
|
||||||
|
'sector:materials',
|
||||||
|
'source:docs.vega.xyz',
|
||||||
|
],
|
||||||
|
priceMonitoringParameters: {
|
||||||
|
triggers: [
|
||||||
|
{
|
||||||
|
horizon: '43200',
|
||||||
|
probability: '0.9999999',
|
||||||
|
auctionExtension: '600',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
liquidityMonitoringParameters: {
|
||||||
|
targetStakeParameters: {
|
||||||
|
timeWindow: '3600',
|
||||||
|
scalingFactor: 10,
|
||||||
|
},
|
||||||
|
triggeringRatio: '0.7',
|
||||||
|
auctionExtension: '1',
|
||||||
|
},
|
||||||
|
logNormal: {
|
||||||
|
tau: 0.0001140771161,
|
||||||
|
riskAversionParameter: 0.01,
|
||||||
|
params: {
|
||||||
|
mu: 0,
|
||||||
|
r: 0.016,
|
||||||
|
sigma: 0.5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
successor: {
|
||||||
|
parentMarketId: parentMarketId,
|
||||||
|
insurancePoolFraction: '0.75',
|
||||||
|
},
|
||||||
|
liquiditySlaParameters: {
|
||||||
|
priceRange: '0.95',
|
||||||
|
commitmentMinTimeFraction: '0.5',
|
||||||
|
performanceHysteresisEpochs: 2,
|
||||||
|
slaCompetitionFactor: '0.75',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
closingTimestamp,
|
||||||
|
enactmentTimestamp,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNewAssetTxBody() {
|
||||||
|
const MIN_CLOSE_SEC = 500;
|
||||||
|
const MIN_ENACT_SEC = 700;
|
||||||
|
const MIN_VALID_SEC = 60;
|
||||||
|
|
||||||
|
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||||
|
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
||||||
|
const validationDate = addSeconds(new Date(), MIN_VALID_SEC);
|
||||||
|
|
||||||
|
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||||
|
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
||||||
|
const validationTimestamp = millisecondsToSeconds(validationDate.getTime());
|
||||||
|
|
||||||
|
return {
|
||||||
|
proposalSubmission: {
|
||||||
|
rationale: {
|
||||||
|
title: 'Test new asset proposal',
|
||||||
|
description: 'E2E test for proposals',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
newAsset: {
|
||||||
|
changes: {
|
||||||
|
name: 'USDT Coin',
|
||||||
|
symbol: 'USDT',
|
||||||
|
decimals: '18',
|
||||||
|
quantum: '1',
|
||||||
|
erc20: {
|
||||||
|
contractAddress: '0xb404c51bbc10dcbe948077f18a4b8e553d160084',
|
||||||
|
withdrawThreshold: '10',
|
||||||
|
lifetimeLimit: '10',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
closingTimestamp,
|
||||||
|
enactmentTimestamp,
|
||||||
|
validationTimestamp,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_TENDERMINT_URL=http://localhost:26617
|
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
|
||||||
NX_VEGA_ENV=CUSTOM
|
NX_VEGA_ENV=CUSTOM
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_TXS_LIST=0
|
NX_EXPLORER_TXS_LIST=0
|
||||||
|
|
||||||
|
NX_TENDERMINT_URL=http://localhost:26617
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
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_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
NX_VEGA_ENV=DEVNET
|
NX_VEGA_ENV=DEVNET
|
||||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||||
@@ -10,3 +8,7 @@ NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
|||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_TENDERMINT_URL=https://be.vega.community
|
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
|
||||||
NX_SENTRY_DSN=https://b3a56b03eda842faad731f3ea9dfd1bc@o286262.ingest.sentry.io/6242427
|
NX_SENTRY_DSN=https://b3a56b03eda842faad731f3ea9dfd1bc@o286262.ingest.sentry.io/6242427
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
@@ -11,3 +9,7 @@ NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
||||||
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
NX_TENDERMINT_URL=https://be.vega.community
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
# App configuration variables
|
# 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_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_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_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
||||||
@@ -11,3 +9,7 @@ NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
||||||
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
# .env is stagnet1, so there are no overrides required
|
# .env is stagnet1, so there are no overrides required
|
||||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}'
|
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}'
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
|
||||||
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml
|
||||||
NX_VEGA_ENV=TESTNET
|
NX_VEGA_ENV=TESTNET
|
||||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||||
@@ -11,3 +9,7 @@ NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||||
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9
|
|||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
|
||||||
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks
|
NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
||||||
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/
|
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ NX_BLOCK_EXPLORER=
|
|||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
"executor": "nx:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"options": {
|
"options": {
|
||||||
"commands": [
|
"commands": [
|
||||||
"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"
|
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.72.3/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
||||||
import { useRef, useLayoutEffect } from 'react';
|
import { useRef, useLayoutEffect } from 'react';
|
||||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export const Footer = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="grid grid-rows-2 lg:grid-cols-[1fr_auto] text-xs md:text-md lg:flex md:col-span-2 px-4 py-2 gap-4 border-t border-vega-light-200 dark:border-vega-dark-200">
|
<footer className="grid grid-cols-[1fr_auto] items-center text-xs md:text-md lg:flex md:col-span-2 px-4 pt-2 pb-3 gap-4 border-t border-vega-light-200 dark:border-vega-dark-200">
|
||||||
<div className="flex justify-between gap-2 align-middle">
|
<div className="flex justify-between gap-2 align-middle">
|
||||||
{GIT_COMMIT_HASH && (
|
{GIT_COMMIT_HASH && (
|
||||||
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
||||||
@@ -43,9 +43,12 @@ export const Footer = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="content-center flex pl-2 md:border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
<div className="content-center flex pr-4 md:border-r border-neutral-700 dark:border-neutral-300">
|
||||||
{VEGA_URL && <NodeUrl url={VEGA_URL} />}
|
<span className="pr-2">{VEGA_URL && <NodeUrl url={VEGA_URL} />}</span>
|
||||||
<Link className="ml-2" onClick={() => setNodeSwitcherOpen(true)}>
|
<Link
|
||||||
|
className="ml-2 underline-offset-4"
|
||||||
|
onClick={() => setNodeSwitcherOpen(true)}
|
||||||
|
>
|
||||||
{t('Change')}
|
{t('Change')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -59,7 +62,10 @@ export const Footer = () => {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="pl-2 align-center lg:align-right lg:flex lg:justify-end gap-2 align-middle lg:max-w-xs lg:ml-auto">
|
<div className="pl-2 align-center lg:align-right lg:flex lg:justify-end gap-2 align-middle lg:max-w-xs lg:ml-auto">
|
||||||
<RouteLink to={`/${Routes.DISCLAIMER}`} className="underline">
|
<RouteLink
|
||||||
|
to={`/${Routes.DISCLAIMER}`}
|
||||||
|
className="underline underline-offset-4"
|
||||||
|
>
|
||||||
Disclaimer
|
Disclaimer
|
||||||
</RouteLink>
|
</RouteLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -95,7 +95,10 @@ export const Header = () => {
|
|||||||
{mainItems.map(routeToNavigationItem)}
|
{mainItems.map(routeToNavigationItem)}
|
||||||
{groupedItems && groupedItems.length > 0 && (
|
{groupedItems && groupedItems.length > 0 && (
|
||||||
<NavigationItem>
|
<NavigationItem>
|
||||||
<NavigationTrigger isActive={Boolean(isOnOther)}>
|
<NavigationTrigger
|
||||||
|
isActive={Boolean(isOnOther)}
|
||||||
|
data-testid="other"
|
||||||
|
>
|
||||||
{t('Other')}
|
{t('Other')}
|
||||||
</NavigationTrigger>
|
</NavigationTrigger>
|
||||||
<NavigationContent>
|
<NavigationContent>
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ query ExplorerMarket($id: ID!) {
|
|||||||
decimals
|
decimals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
... on Perpetual {
|
||||||
|
quoteName
|
||||||
|
settlementAsset {
|
||||||
|
decimals
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -8,7 +8,7 @@ export type ExplorerMarketQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } } } } | null };
|
export type ExplorerMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } | { __typename?: 'Perpetual', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } | { __typename?: 'Spot' } } } } | null };
|
||||||
|
|
||||||
|
|
||||||
export const ExplorerMarketDocument = gql`
|
export const ExplorerMarketDocument = gql`
|
||||||
@@ -27,6 +27,12 @@ export const ExplorerMarketDocument = gql`
|
|||||||
decimals
|
decimals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
... on Perpetual {
|
||||||
|
quoteName
|
||||||
|
settlementAsset {
|
||||||
|
decimals
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ describe('Market link component', () => {
|
|||||||
instrument: {
|
instrument: {
|
||||||
name: 'test-label',
|
name: 'test-label',
|
||||||
product: {
|
product: {
|
||||||
|
__typename: 'Future',
|
||||||
quoteName: 'dai',
|
quoteName: 'dai',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,34 +1,41 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||||
import { PriceMonitoringBoundsInfoPanel } from '@vegaprotocol/markets';
|
import {
|
||||||
|
LiquidityPriceRangeInfoPanel,
|
||||||
|
LiquiditySLAParametersInfoPanel,
|
||||||
|
MarginScalingFactorsPanel,
|
||||||
|
PriceMonitoringBoundsInfoPanel,
|
||||||
|
SuccessionLineInfoPanel,
|
||||||
|
getDataSourceSpecForSettlementData,
|
||||||
|
getDataSourceSpecForTradingTermination,
|
||||||
|
} from '@vegaprotocol/markets';
|
||||||
import {
|
import {
|
||||||
LiquidityInfoPanel,
|
LiquidityInfoPanel,
|
||||||
LiquidityMonitoringParametersInfoPanel,
|
LiquidityMonitoringParametersInfoPanel,
|
||||||
InstrumentInfoPanel,
|
InstrumentInfoPanel,
|
||||||
KeyDetailsInfoPanel,
|
KeyDetailsInfoPanel,
|
||||||
LiquidityPriceRangeInfoPanel,
|
|
||||||
MetadataInfoPanel,
|
MetadataInfoPanel,
|
||||||
OracleInfoPanel,
|
OracleInfoPanel,
|
||||||
RiskFactorsInfoPanel,
|
RiskFactorsInfoPanel,
|
||||||
RiskModelInfoPanel,
|
RiskModelInfoPanel,
|
||||||
RiskParametersInfoPanel,
|
|
||||||
SettlementAssetInfoPanel,
|
SettlementAssetInfoPanel,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import { MarketInfoTable } from '@vegaprotocol/markets';
|
import { MarketInfoTable } from '@vegaprotocol/markets';
|
||||||
import type { DataSourceDefinition } from '@vegaprotocol/types';
|
import type { DataSourceFragment } from '@vegaprotocol/markets';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
|
||||||
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||||
if (!market) return null;
|
if (!market) return null;
|
||||||
|
const { product } = market.tradableInstrument.instrument;
|
||||||
|
const settlementDataSource = getDataSourceSpecForSettlementData(product);
|
||||||
|
const terminationDataSource = getDataSourceSpecForTradingTermination(product);
|
||||||
|
|
||||||
const settlementData = market.tradableInstrument.instrument.product
|
const getSigners = ({ data }: DataSourceFragment) => {
|
||||||
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
|
|
||||||
const terminationData = market.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
|
|
||||||
|
|
||||||
const getSigners = (data: DataSourceDefinition) => {
|
|
||||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||||
const signers = data.sourceType.sourceType.signers || [];
|
const signers =
|
||||||
|
('signers' in data.sourceType.sourceType &&
|
||||||
|
data.sourceType.sourceType.signers) ||
|
||||||
|
[];
|
||||||
|
|
||||||
return signers.map(({ signer }, i) => {
|
return signers.map(({ signer }, i) => {
|
||||||
return (
|
return (
|
||||||
@@ -40,10 +47,13 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const showTwoOracles = isEqual(
|
const showTwoOracles =
|
||||||
getSigners(settlementData),
|
settlementDataSource &&
|
||||||
getSigners(terminationData)
|
terminationDataSource &&
|
||||||
);
|
isEqual(
|
||||||
|
getSigners(settlementDataSource),
|
||||||
|
getSigners(terminationDataSource)
|
||||||
|
);
|
||||||
|
|
||||||
const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2';
|
const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2';
|
||||||
|
|
||||||
@@ -59,8 +69,8 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
<MetadataInfoPanel market={market} />
|
<MetadataInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Risk model')}</h2>
|
<h2 className={headerClassName}>{t('Risk model')}</h2>
|
||||||
<RiskModelInfoPanel market={market} />
|
<RiskModelInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Risk parameters')}</h2>
|
<h2 className={headerClassName}>{t('Margin scaling factors')}</h2>
|
||||||
<RiskParametersInfoPanel market={market} />
|
<MarginScalingFactorsPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Risk factors')}</h2>
|
<h2 className={headerClassName}>{t('Risk factors')}</h2>
|
||||||
<RiskFactorsInfoPanel market={market} />
|
<RiskFactorsInfoPanel market={market} />
|
||||||
{(market.data?.priceMonitoringBounds || []).map((trigger, i) => (
|
{(market.data?.priceMonitoringBounds || []).map((trigger, i) => (
|
||||||
@@ -86,10 +96,12 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
)}
|
)}
|
||||||
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
||||||
<LiquidityMonitoringParametersInfoPanel market={market} />
|
<LiquidityMonitoringParametersInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Liquidity')}</h2>
|
|
||||||
<LiquidityInfoPanel market={market} />
|
|
||||||
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
||||||
<LiquidityPriceRangeInfoPanel market={market} />
|
<LiquidityPriceRangeInfoPanel market={market} />
|
||||||
|
<h2 className={headerClassName}>{t('Liquidity SLA protocol')}</h2>
|
||||||
|
<LiquiditySLAParametersInfoPanel market={market} />
|
||||||
|
<h2 className={headerClassName}>{t('Liquidity')}</h2>
|
||||||
|
<LiquidityInfoPanel market={market} />
|
||||||
{showTwoOracles ? (
|
{showTwoOracles ? (
|
||||||
<>
|
<>
|
||||||
<h2 className={headerClassName}>{t('Settlement oracle')}</h2>
|
<h2 className={headerClassName}>{t('Settlement oracle')}</h2>
|
||||||
@@ -103,6 +115,8 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
<OracleInfoPanel market={market} type="settlementData" />
|
<OracleInfoPanel market={market} type="settlementData" />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<h2 className={`${headerClassName} mb-4`}>{t('Succession line')}</h2>
|
||||||
|
<SuccessionLineInfoPanel market={market} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import type { MarketFieldsFragment } from '@vegaprotocol/markets';
|
import { getAsset, type MarketFieldsFragment } from '@vegaprotocol/markets';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import type { ColDef } from 'ag-grid-community';
|
import type { ColDef } from 'ag-grid-community';
|
||||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import type {
|
import type {
|
||||||
VegaICellRendererParams,
|
VegaICellRendererParams,
|
||||||
VegaValueGetterParams,
|
VegaValueGetterParams,
|
||||||
@@ -73,8 +73,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
MarketFieldsFragment,
|
MarketFieldsFragment,
|
||||||
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
||||||
>) => {
|
>) => {
|
||||||
const value =
|
const value = data && getAsset(data);
|
||||||
data?.tradableInstrument.instrument.product.settlementAsset;
|
|
||||||
return value ? (
|
return value ? (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ fragment ExplorerDeterministicOrderFields on Order {
|
|||||||
... on Future {
|
... on Future {
|
||||||
quoteName
|
quoteName
|
||||||
}
|
}
|
||||||
|
... on Perpetual {
|
||||||
|
quoteName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
fragment ExplorerStopOrderFields on StopOrder {
|
||||||
|
id
|
||||||
|
status
|
||||||
|
createdAt
|
||||||
|
trigger {
|
||||||
|
... on StopOrderPrice {
|
||||||
|
price
|
||||||
|
}
|
||||||
|
... on StopOrderTrailingPercentOffset {
|
||||||
|
trailingPercentOffset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createdAt
|
||||||
|
ocoLinkId
|
||||||
|
triggerDirection
|
||||||
|
order {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query ExplorerStopOrder($stopOrderId: ID!) {
|
||||||
|
stopOrder(id: $stopOrderId) {
|
||||||
|
...ExplorerStopOrderFields
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import * as Types from '@vegaprotocol/types';
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import * as Apollo from '@apollo/client';
|
import * as Apollo from '@apollo/client';
|
||||||
const defaultOptions = {} as const;
|
const defaultOptions = {} as const;
|
||||||
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } };
|
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } | { __typename?: 'Perpetual', quoteName: string } | { __typename?: 'Spot' } } } } };
|
||||||
|
|
||||||
export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
||||||
orderId: Types.Scalars['ID'];
|
orderId: Types.Scalars['ID'];
|
||||||
@@ -11,7 +11,7 @@ export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } } };
|
export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } | { __typename?: 'Perpetual', quoteName: string } | { __typename?: 'Spot' } } } } } };
|
||||||
|
|
||||||
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
||||||
fragment ExplorerDeterministicOrderFields on Order {
|
fragment ExplorerDeterministicOrderFields on Order {
|
||||||
@@ -47,6 +47,9 @@ export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
|||||||
... on Future {
|
... on Future {
|
||||||
quoteName
|
quoteName
|
||||||
}
|
}
|
||||||
|
... on Perpetual {
|
||||||
|
quoteName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type ExplorerStopOrderFieldsFragment = { __typename?: 'StopOrder', id: string, status: Types.StopOrderStatus, createdAt: any, ocoLinkId?: string | null, triggerDirection: Types.StopOrderTriggerDirection, trigger: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string }, order?: { __typename?: 'Order', id: string } | null };
|
||||||
|
|
||||||
|
export type ExplorerStopOrderQueryVariables = Types.Exact<{
|
||||||
|
stopOrderId: Types.Scalars['ID'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ExplorerStopOrderQuery = { __typename?: 'Query', stopOrder?: { __typename?: 'StopOrder', id: string, status: Types.StopOrderStatus, createdAt: any, ocoLinkId?: string | null, triggerDirection: Types.StopOrderTriggerDirection, trigger: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string }, order?: { __typename?: 'Order', id: string } | null } | null };
|
||||||
|
|
||||||
|
export const ExplorerStopOrderFieldsFragmentDoc = gql`
|
||||||
|
fragment ExplorerStopOrderFields on StopOrder {
|
||||||
|
id
|
||||||
|
status
|
||||||
|
createdAt
|
||||||
|
trigger {
|
||||||
|
... on StopOrderPrice {
|
||||||
|
price
|
||||||
|
}
|
||||||
|
... on StopOrderTrailingPercentOffset {
|
||||||
|
trailingPercentOffset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createdAt
|
||||||
|
ocoLinkId
|
||||||
|
triggerDirection
|
||||||
|
order {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export const ExplorerStopOrderDocument = gql`
|
||||||
|
query ExplorerStopOrder($stopOrderId: ID!) {
|
||||||
|
stopOrder(id: $stopOrderId) {
|
||||||
|
...ExplorerStopOrderFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
${ExplorerStopOrderFieldsFragmentDoc}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useExplorerStopOrderQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useExplorerStopOrderQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useExplorerStopOrderQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = useExplorerStopOrderQuery({
|
||||||
|
* variables: {
|
||||||
|
* stopOrderId: // value for 'stopOrderId'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useExplorerStopOrderQuery(baseOptions: Apollo.QueryHookOptions<ExplorerStopOrderQuery, ExplorerStopOrderQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ExplorerStopOrderQuery, ExplorerStopOrderQueryVariables>(ExplorerStopOrderDocument, options);
|
||||||
|
}
|
||||||
|
export function useExplorerStopOrderLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerStopOrderQuery, ExplorerStopOrderQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ExplorerStopOrderQuery, ExplorerStopOrderQueryVariables>(ExplorerStopOrderDocument, options);
|
||||||
|
}
|
||||||
|
export type ExplorerStopOrderQueryHookResult = ReturnType<typeof useExplorerStopOrderQuery>;
|
||||||
|
export type ExplorerStopOrderLazyQueryHookResult = ReturnType<typeof useExplorerStopOrderLazyQuery>;
|
||||||
|
export type ExplorerStopOrderQueryResult = Apollo.QueryResult<ExplorerStopOrderQuery, ExplorerStopOrderQueryVariables>;
|
||||||
@@ -150,6 +150,7 @@ function renderExistingAmend(
|
|||||||
instrument: {
|
instrument: {
|
||||||
name: 'test-label',
|
name: 'test-label',
|
||||||
product: {
|
product: {
|
||||||
|
__typename: 'Future',
|
||||||
quoteName: 'dai',
|
quoteName: 'dai',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ describe('Order TX Summary component', () => {
|
|||||||
expect(res.queryByTestId('order-summary')).not.toBeInTheDocument();
|
expect(res.queryByTestId('order-summary')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Renders nothing if the order passed lacks a price', () => {
|
it('Renders "Market Price" if the order passed lacks a price', () => {
|
||||||
const o: Order = {
|
const o: Order = {
|
||||||
marketId: '123',
|
marketId: '123',
|
||||||
side: 'SIDE_BUY',
|
side: 'SIDE_BUY',
|
||||||
@@ -41,7 +41,7 @@ describe('Order TX Summary component', () => {
|
|||||||
size: '10',
|
size: '10',
|
||||||
};
|
};
|
||||||
const res = renderComponent(o);
|
const res = renderComponent(o);
|
||||||
expect(res.queryByTestId('order-summary')).not.toBeInTheDocument();
|
expect(res.queryByText('Market Price')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Renders nothing if the order has an unspecified side', () => {
|
it('Renders nothing if the order has an unspecified side', () => {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { components } from '../../../types/explorer';
|
|||||||
import PriceInMarket from '../price-in-market/price-in-market';
|
import PriceInMarket from '../price-in-market/price-in-market';
|
||||||
import { sideText } from '../order-details/lib/order-labels';
|
import { sideText } from '../order-details/lib/order-labels';
|
||||||
import SizeInMarket from '../size-in-market/size-in-market';
|
import SizeInMarket from '../size-in-market/size-in-market';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
export type OrderSummaryProps = {
|
export type OrderSummaryProps = {
|
||||||
order: components['schemas']['v1OrderSubmission'];
|
order: components['schemas']['v1OrderSubmission'];
|
||||||
@@ -20,7 +21,6 @@ const OrderTxSummary = ({ order }: OrderSummaryProps) => {
|
|||||||
if (
|
if (
|
||||||
!order ||
|
!order ||
|
||||||
!order.marketId ||
|
!order.marketId ||
|
||||||
!order.price ||
|
|
||||||
!order.side ||
|
!order.side ||
|
||||||
order.side === 'SIDE_UNSPECIFIED'
|
order.side === 'SIDE_UNSPECIFIED'
|
||||||
) {
|
) {
|
||||||
@@ -36,10 +36,14 @@ const OrderTxSummary = ({ order }: OrderSummaryProps) => {
|
|||||||
'-'
|
'-'
|
||||||
)}
|
)}
|
||||||
<i className="text-xs">@</i>
|
<i className="text-xs">@</i>
|
||||||
<PriceInMarket
|
{order.price ? (
|
||||||
marketId={order.marketId}
|
<PriceInMarket
|
||||||
price={order.price}
|
marketId={order.marketId}
|
||||||
></PriceInMarket>
|
price={order.price}
|
||||||
|
></PriceInMarket>
|
||||||
|
) : (
|
||||||
|
t('Market Price')
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ const PriceInMarket = ({
|
|||||||
label = addDecimalsFormatNumber(price, data.market.decimalPlaces);
|
label = addDecimalsFormatNumber(price, data.market.decimalPlaces);
|
||||||
} else if (
|
} else if (
|
||||||
decimalSource === 'SETTLEMENT_ASSET' &&
|
decimalSource === 'SETTLEMENT_ASSET' &&
|
||||||
|
data.market &&
|
||||||
|
'settlementAsset' in data.market.tradableInstrument.instrument.product &&
|
||||||
data.market?.tradableInstrument.instrument.product.settlementAsset
|
data.market?.tradableInstrument.instrument.product.settlementAsset
|
||||||
) {
|
) {
|
||||||
label = addDecimalsFormatNumber(
|
label = addDecimalsFormatNumber(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
|||||||
import { VoteProgress } from '@vegaprotocol/proposals';
|
import { VoteProgress } from '@vegaprotocol/proposals';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import type {
|
import type {
|
||||||
VegaICellRendererParams,
|
VegaICellRendererParams,
|
||||||
VegaValueFormatterParams,
|
VegaValueFormatterParams,
|
||||||
@@ -33,7 +33,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
const { params } = useNetworkParams([
|
const { params } = useNetworkParams([
|
||||||
NetworkParams.governance_proposal_market_requiredMajority,
|
NetworkParams.governance_proposal_market_requiredMajority,
|
||||||
]);
|
]);
|
||||||
const tokenLink = useLinks(DApp.Token);
|
const tokenLink = useLinks(DApp.Governance);
|
||||||
const requiredMajorityPercentage = useMemo(() => {
|
const requiredMajorityPercentage = useMemo(() => {
|
||||||
const requiredMajority =
|
const requiredMajority =
|
||||||
params?.governance_proposal_market_requiredMajority ?? 1;
|
params?.governance_proposal_market_requiredMajority ?? 1;
|
||||||
@@ -105,7 +105,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
? new BigNumber(0)
|
? new BigNumber(0)
|
||||||
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
||||||
return (
|
return (
|
||||||
<div className="uppercase flex h-full items-center justify-center pt-2">
|
<div className="flex items-center justify-center h-full pt-2 uppercase">
|
||||||
<VoteProgress
|
<VoteProgress
|
||||||
threshold={requiredMajorityPercentage}
|
threshold={requiredMajorityPercentage}
|
||||||
progress={yesPercentage}
|
progress={yesPercentage}
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import { formatNumberPercentage } from '@vegaprotocol/utils';
|
||||||
|
import BigNumber from 'bignumber.js';
|
||||||
|
import PriceInMarket from '../../../price-in-market/price-in-market';
|
||||||
|
import StopOrderTriggerSummary from './stop-order-trigger';
|
||||||
|
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import fromUnixTime from 'date-fns/fromUnixTime';
|
||||||
|
|
||||||
|
const wrapperClasses =
|
||||||
|
'flex-1 max-w-xs items-center border border-vega-light-200 dark:border-vega-dark-150 rounded-md pv-2 ph-5 mb-5';
|
||||||
|
|
||||||
|
export type StopOrderType = 'RisesAbove' | 'FallsBelow' | 'OCO';
|
||||||
|
type V1OrderSetup = components['schemas']['v1StopOrderSetup'];
|
||||||
|
|
||||||
|
interface StopOrderSetupProps extends V1OrderSetup {
|
||||||
|
type: StopOrderType;
|
||||||
|
deterministicId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getExpiryTypeLabel(
|
||||||
|
expiryStrategy: V1OrderSetup['expiryStrategy']
|
||||||
|
): string {
|
||||||
|
switch (expiryStrategy) {
|
||||||
|
case 'EXPIRY_STRATEGY_CANCELS':
|
||||||
|
return t('Cancels');
|
||||||
|
case 'EXPIRY_STRATEGY_SUBMIT':
|
||||||
|
return t('Submit');
|
||||||
|
}
|
||||||
|
|
||||||
|
return expiryStrategy || t('Unknown');
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExpiryTriggerProps {
|
||||||
|
trailingPercentOffset?: string;
|
||||||
|
price?: string;
|
||||||
|
marketId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ExpiryTrigger({
|
||||||
|
trailingPercentOffset,
|
||||||
|
price,
|
||||||
|
marketId,
|
||||||
|
}: ExpiryTriggerProps) {
|
||||||
|
if (price && marketId) {
|
||||||
|
return <PriceInMarket price={price} marketId={marketId} />;
|
||||||
|
}
|
||||||
|
if (trailingPercentOffset) {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{formatNumberPercentage(new BigNumber(trailingPercentOffset))}{' '}
|
||||||
|
(trailing)
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMovePrefix(
|
||||||
|
type: StopOrderType,
|
||||||
|
trailingPercentOffset?: string
|
||||||
|
): string {
|
||||||
|
if (type === 'RisesAbove') {
|
||||||
|
if (trailingPercentOffset) {
|
||||||
|
return '+';
|
||||||
|
} else {
|
||||||
|
return '>';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (trailingPercentOffset) {
|
||||||
|
return '-';
|
||||||
|
} else {
|
||||||
|
return '<';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TypeLabel = {
|
||||||
|
RisesAbove: t('Rises above ↗'),
|
||||||
|
FallsBelow: t('Falls below ↘'),
|
||||||
|
OCO: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export const StopOrderSetup = ({
|
||||||
|
type,
|
||||||
|
price,
|
||||||
|
orderSubmission,
|
||||||
|
expiresAt,
|
||||||
|
expiryStrategy,
|
||||||
|
trailingPercentOffset,
|
||||||
|
deterministicId,
|
||||||
|
}: StopOrderSetupProps) => {
|
||||||
|
let d = 'Unknown';
|
||||||
|
try {
|
||||||
|
d = expiresAt
|
||||||
|
? fromUnixTime(parseInt(expiresAt) / 1000000000).toLocaleString()
|
||||||
|
: t('Unknown');
|
||||||
|
} catch (e) {
|
||||||
|
d = t('Unknown');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={wrapperClasses}>
|
||||||
|
<div className="mb-12 lg:mb-0">
|
||||||
|
<div className="bg-slate-100 text-slate-900 px-6 py-2 md:px-6 flex">
|
||||||
|
<div className="flex-1">
|
||||||
|
<strong className="font-bold mb-1">{TypeLabel[type]} </strong>
|
||||||
|
<p className=" font-xs mb-0">
|
||||||
|
{getMovePrefix(type, trailingPercentOffset)}
|
||||||
|
<ExpiryTrigger
|
||||||
|
trailingPercentOffset={trailingPercentOffset}
|
||||||
|
price={price}
|
||||||
|
marketId={orderSubmission?.marketId}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{expiresAt && expiryStrategy ? (
|
||||||
|
<div className="flex-1">
|
||||||
|
<strong className="font-bold mb-1">{t('Expiry Type')}</strong>
|
||||||
|
<p className=" font-xs mb-0">
|
||||||
|
<Tooltip description={<span>{d}</span>}>
|
||||||
|
<span>{getExpiryTypeLabel(expiryStrategy)}</span>
|
||||||
|
</Tooltip>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
<StopOrderTriggerSummary
|
||||||
|
id={deterministicId}
|
||||||
|
orderSubmission={orderSubmission}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { StopOrderStatus } from '@vegaprotocol/types';
|
||||||
|
import { useExplorerStopOrderQuery } from '../../../order-details/__generated__/StopOrder';
|
||||||
|
import type { ExplorerStopOrderQuery } from '../../../order-details/__generated__/StopOrder';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { Icon } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import type { IconName } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import OrderTxSummary from '../../../order-summary/order-tx-summary';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import type { ApolloError } from '@apollo/client';
|
||||||
|
|
||||||
|
export const StatusLabel: Record<StopOrderStatus, string> = {
|
||||||
|
[StopOrderStatus.STATUS_CANCELLED]: t('Cancelled'),
|
||||||
|
[StopOrderStatus.STATUS_EXPIRED]: t('Expired'),
|
||||||
|
[StopOrderStatus.STATUS_PENDING]: t('Pending'),
|
||||||
|
[StopOrderStatus.STATUS_REJECTED]: t('Rejected'),
|
||||||
|
[StopOrderStatus.STATUS_STOPPED]: t('Stopped'),
|
||||||
|
[StopOrderStatus.STATUS_TRIGGERED]: t('Triggered'),
|
||||||
|
[StopOrderStatus.STATUS_UNSPECIFIED]: t('Status unknown'),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StatusIcon: Record<StopOrderStatus, IconName> = {
|
||||||
|
[StopOrderStatus.STATUS_CANCELLED]: 'disable',
|
||||||
|
[StopOrderStatus.STATUS_EXPIRED]: 'outdated',
|
||||||
|
[StopOrderStatus.STATUS_PENDING]: 'circle',
|
||||||
|
[StopOrderStatus.STATUS_REJECTED]: 'cross',
|
||||||
|
[StopOrderStatus.STATUS_STOPPED]: 'stop',
|
||||||
|
[StopOrderStatus.STATUS_TRIGGERED]: 'tick',
|
||||||
|
[StopOrderStatus.STATUS_UNSPECIFIED]: 'help',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StatusMidColor: Record<StopOrderStatus, string> = {
|
||||||
|
[StopOrderStatus.STATUS_CANCELLED]: 'bg-red-100 text-red-900',
|
||||||
|
[StopOrderStatus.STATUS_EXPIRED]: 'bg-red-100 text-red-900',
|
||||||
|
[StopOrderStatus.STATUS_PENDING]: 'bg-yellow-100 text-yellow-900',
|
||||||
|
[StopOrderStatus.STATUS_REJECTED]: 'bg-red-100 text-red-900',
|
||||||
|
[StopOrderStatus.STATUS_STOPPED]: 'bg-red-100 text-red-900',
|
||||||
|
[StopOrderStatus.STATUS_TRIGGERED]: 'bg-green-100 text-green-900',
|
||||||
|
[StopOrderStatus.STATUS_UNSPECIFIED]: 'bg-yellow-100 text-yellow-900',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StatusBottomColor: Record<StopOrderStatus, string> = {
|
||||||
|
[StopOrderStatus.STATUS_CANCELLED]: 'bg-red-50 text-red-900 line-through',
|
||||||
|
[StopOrderStatus.STATUS_EXPIRED]: 'bg-red-50 text-red-900 line-through',
|
||||||
|
[StopOrderStatus.STATUS_PENDING]: 'bg-yellow-50 text-yellow-900',
|
||||||
|
[StopOrderStatus.STATUS_REJECTED]: 'bg-red-50 text-red-900 line-through',
|
||||||
|
[StopOrderStatus.STATUS_STOPPED]: 'bg-red-50 text-red-900 line-through',
|
||||||
|
[StopOrderStatus.STATUS_TRIGGERED]: 'bg-green-50 text-green-900',
|
||||||
|
[StopOrderStatus.STATUS_UNSPECIFIED]:
|
||||||
|
'bg-yellow-50 text-yellow-900 line-through',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getStopOrderTriggerStatus(
|
||||||
|
data?: ExplorerStopOrderQuery,
|
||||||
|
error?: ApolloError
|
||||||
|
) {
|
||||||
|
if (data && data.stopOrder) {
|
||||||
|
return data.stopOrder.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return StopOrderStatus.STATUS_UNSPECIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StopOrderTriggerSummaryProps {
|
||||||
|
id: string;
|
||||||
|
orderSubmission?: components['schemas']['v1OrderSubmission'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
const StopOrderTriggerSummary = ({
|
||||||
|
id,
|
||||||
|
orderSubmission,
|
||||||
|
}: StopOrderTriggerSummaryProps) => {
|
||||||
|
const { data, error } = useExplorerStopOrderQuery({
|
||||||
|
variables: { stopOrderId: id },
|
||||||
|
});
|
||||||
|
|
||||||
|
const status = getStopOrderTriggerStatus(data, error);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={`${StatusMidColor[status]} px-3 py-2 md:px-6 flex space-x-4`}
|
||||||
|
>
|
||||||
|
<p className="m-0 p-0 align-top">
|
||||||
|
<Icon
|
||||||
|
size={6}
|
||||||
|
name={StatusIcon[status]}
|
||||||
|
className="inline-block mr-2"
|
||||||
|
/>
|
||||||
|
<span className="align-top">{StatusLabel[status]}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`${StatusBottomColor[status]} px-3 py-2 md:px-6 flex space-x-4`}
|
||||||
|
>
|
||||||
|
{orderSubmission && (
|
||||||
|
<p className="text-vega-grey-400 strike">
|
||||||
|
<OrderTxSummary order={orderSubmission} />
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StopOrderTriggerSummary;
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import SizeInMarket from '../../../size-in-market/size-in-market';
|
||||||
|
|
||||||
|
export interface TxDetailsOrderIcebergDetailsProps {
|
||||||
|
iceberg: components['schemas']['v1IcebergOpts'];
|
||||||
|
size: components['schemas']['v1OrderSubmission']['size'];
|
||||||
|
marketId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
.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,
|
||||||
|
marketId,
|
||||||
|
}: 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">
|
||||||
|
{marketId ? (
|
||||||
|
<SizeInMarket
|
||||||
|
size={iceberg.minimumVisibleSize}
|
||||||
|
marketId={marketId}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
iceberg.minimumVisibleSize
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip description={t('Iceberg: Total size')}>
|
||||||
|
<span className="text-sm text-vega-blue-600 mx-3">
|
||||||
|
{marketId ? <SizeInMarket size={size} marketId={marketId} /> : size}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip description={t('Iceberg: Visible peak')}>
|
||||||
|
<span className="align-top text-vega-yellow-600">
|
||||||
|
{marketId ? (
|
||||||
|
<SizeInMarket size={iceberg.peakSize} marketId={marketId} />
|
||||||
|
) : (
|
||||||
|
iceberg.peakSize
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
+1
-1
@@ -35,7 +35,7 @@ export const BundleSigners = ({
|
|||||||
tx,
|
tx,
|
||||||
id,
|
id,
|
||||||
}: BundleSignersProps) => {
|
}: BundleSignersProps) => {
|
||||||
const tokenLink = useLinks(DApp.Token);
|
const tokenLink = useLinks(DApp.Governance);
|
||||||
|
|
||||||
const bridgeFunction: BridgeFunction =
|
const bridgeFunction: BridgeFunction =
|
||||||
tx?.changes?.erc20 && 'contractAddress' in tx.changes.erc20
|
tx?.changes?.erc20 && 'contractAddress' in tx.changes.erc20
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ export const sharedHeaderProps = {
|
|||||||
className: 'align-top',
|
className: 'align-top',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Labels: Record<BlockExplorerTransactionResult['type'], string> = {
|
||||||
|
'Stop Orders Submission': 'Stop Order',
|
||||||
|
'Stop Orders Cancellation': 'Cancel Stop Order',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These rows are shown for every transaction type, providing a consistent set of rows for the top
|
* These rows are shown for every transaction type, providing a consistent set of rows for the top
|
||||||
* of a transaction details row. The order is relatively arbitrary but felt right - it might need to
|
* of a transaction details row. The order is relatively arbitrary but felt right - it might need to
|
||||||
@@ -44,12 +49,14 @@ export const TxDetailsShared = ({
|
|||||||
const time: string = blockData?.result.block.header.time || '';
|
const time: string = blockData?.result.block.header.time || '';
|
||||||
const height: string = blockData?.result.block.header.height || txData.block;
|
const height: string = blockData?.result.block.header.height || txData.block;
|
||||||
|
|
||||||
|
const type = Labels[txData.type] || txData.type;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{hideTypeRow === false ? (
|
{hideTypeRow === false ? (
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell {...sharedHeaderProps}>{t('Type')}</TableCell>
|
<TableCell {...sharedHeaderProps}>{t('Type')}</TableCell>
|
||||||
<TableCell>{txData.type}</TableCell>
|
<TableCell>{type}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : null}
|
) : null}
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ const AccountType: Record<AccountTypes, string> = {
|
|||||||
ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: 'LP Received Fees',
|
ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: 'LP Received Fees',
|
||||||
ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: 'Market Proposers',
|
ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: 'Market Proposers',
|
||||||
ACCOUNT_TYPE_HOLDING: 'Holding',
|
ACCOUNT_TYPE_HOLDING: 'Holding',
|
||||||
|
ACCOUNT_TYPE_LIQUIDITY_FEES_BONUS_DISTRIBUTION: 'Bonus Distribution',
|
||||||
|
ACCOUNT_TYPE_LP_LIQUIDITY_FEES: 'LP Liquidity Fees',
|
||||||
};
|
};
|
||||||
|
|
||||||
interface TransferParticipantsProps {
|
interface TransferParticipantsProps {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { TxDetailsBatch } from './tx-batch';
|
|||||||
import { TxDetailsChainEvent } from './tx-chain-event';
|
import { TxDetailsChainEvent } from './tx-chain-event';
|
||||||
import { TxDetailsNodeVote } from './tx-node-vote';
|
import { TxDetailsNodeVote } from './tx-node-vote';
|
||||||
import { TxDetailsOrderCancel } from './tx-order-cancel';
|
import { TxDetailsOrderCancel } from './tx-order-cancel';
|
||||||
|
import { TxDetailsStopOrderCancel } from './tx-stop-order-cancel';
|
||||||
import { TxDetailsOrderAmend } from './tx-order-amend';
|
import { TxDetailsOrderAmend } from './tx-order-amend';
|
||||||
import { TxDetailsWithdrawSubmission } from './tx-withdraw-submission';
|
import { TxDetailsWithdrawSubmission } from './tx-withdraw-submission';
|
||||||
import { TxDetailsDelegate } from './tx-delegation';
|
import { TxDetailsDelegate } from './tx-delegation';
|
||||||
@@ -26,6 +27,7 @@ import { TxDetailsNodeAnnounce } from './tx-node-announce';
|
|||||||
import { TxDetailsStateVariable } from './tx-state-variable-proposal';
|
import { TxDetailsStateVariable } from './tx-state-variable-proposal';
|
||||||
import { TxProposal } from './tx-proposal';
|
import { TxProposal } from './tx-proposal';
|
||||||
import { TxDetailsTransfer } from './tx-transfer';
|
import { TxDetailsTransfer } from './tx-transfer';
|
||||||
|
import { TxDetailsStopOrderSubmission } from './tx-stop-order-submission';
|
||||||
|
|
||||||
interface TxDetailsWrapperProps {
|
interface TxDetailsWrapperProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -85,6 +87,8 @@ function getTransactionComponent(txData?: BlockExplorerTransactionResult) {
|
|||||||
return TxDetailsProtocolUpgrade;
|
return TxDetailsProtocolUpgrade;
|
||||||
case 'Cancel Order':
|
case 'Cancel Order':
|
||||||
return TxDetailsOrderCancel;
|
return TxDetailsOrderCancel;
|
||||||
|
case 'Stop Orders Cancellation':
|
||||||
|
return TxDetailsStopOrderCancel;
|
||||||
case 'Amend Order':
|
case 'Amend Order':
|
||||||
return TxDetailsOrderAmend;
|
return TxDetailsOrderAmend;
|
||||||
case 'Validator Heartbeat':
|
case 'Validator Heartbeat':
|
||||||
@@ -113,6 +117,8 @@ function getTransactionComponent(txData?: BlockExplorerTransactionResult) {
|
|||||||
return TxDetailsUndelegate;
|
return TxDetailsUndelegate;
|
||||||
case 'State Variable Proposal':
|
case 'State Variable Proposal':
|
||||||
return TxDetailsStateVariable;
|
return TxDetailsStateVariable;
|
||||||
|
case 'Stop Orders Submission':
|
||||||
|
return TxDetailsStopOrderSubmission;
|
||||||
case 'Transfer Funds':
|
case 'Transfer Funds':
|
||||||
return TxDetailsTransfer;
|
return TxDetailsTransfer;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export const TxDetailsIssueSignatures = ({
|
|||||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cmd: Command = txData.command;
|
const cmd: Command = txData.command.issueSignatures;
|
||||||
const k = cmd.kind ? kind[cmd.kind] : null;
|
const k = cmd.kind ? kind[cmd.kind] : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
|||||||
import DeterministicOrderDetails from '../../order-details/deterministic-order-details';
|
import DeterministicOrderDetails from '../../order-details/deterministic-order-details';
|
||||||
import Hash from '../../links/hash';
|
import Hash from '../../links/hash';
|
||||||
import { TxOrderPeggedReferenceRow } from './order/tx-order-peg';
|
import { TxOrderPeggedReferenceRow } from './order/tx-order-peg';
|
||||||
|
import { TxOrderIcebergDetails } from './order/tx-order-iceberg';
|
||||||
|
|
||||||
interface TxDetailsOrderProps {
|
interface TxDetailsOrderProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -32,6 +33,8 @@ export const TxDetailsOrder = ({
|
|||||||
const marketId = txData.command.orderSubmission.marketId || '-';
|
const marketId = txData.command.orderSubmission.marketId || '-';
|
||||||
const reference = txData.command.orderSubmission.peggedOrder;
|
const reference = txData.command.orderSubmission.peggedOrder;
|
||||||
const side = txData.command.orderSubmission.side;
|
const side = txData.command.orderSubmission.side;
|
||||||
|
const iceberg = txData.command.orderSubmission.icebergOpts;
|
||||||
|
const size = txData.command.orderSubmission.size;
|
||||||
|
|
||||||
let deterministicId = '';
|
let deterministicId = '';
|
||||||
|
|
||||||
@@ -74,6 +77,18 @@ export const TxDetailsOrder = ({
|
|||||||
marketId={marketId}
|
marketId={marketId}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
{iceberg ? (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Iceberg details')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<TxOrderIcebergDetails
|
||||||
|
iceberg={iceberg}
|
||||||
|
size={size}
|
||||||
|
marketId={marketId}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : null}
|
||||||
</TableWithTbody>
|
</TableWithTbody>
|
||||||
|
|
||||||
{deterministicId.length > 0 ? (
|
{deterministicId.length > 0 ? (
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import Hash from '../../links/hash';
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ProposalSignatureBundleNewAsset } from './proposal/signature-bundle-new';
|
import { ProposalSignatureBundleNewAsset } from './proposal/signature-bundle-new';
|
||||||
import { ProposalSignatureBundleUpdateAsset } from './proposal/signature-bundle-update';
|
import { ProposalSignatureBundleUpdateAsset } from './proposal/signature-bundle-update';
|
||||||
|
import { MarketLink } from '../../links';
|
||||||
|
import { formatNumber } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
export type Proposal = components['schemas']['v1ProposalSubmission'];
|
export type Proposal = components['schemas']['v1ProposalSubmission'];
|
||||||
export type ProposalTerms = components['schemas']['vegaProposalTerms'];
|
export type ProposalTerms = components['schemas']['vegaProposalTerms'];
|
||||||
@@ -53,7 +55,11 @@ export function proposalTypeLabel(terms?: ProposalTerms): string {
|
|||||||
} else if (has(terms, 'updateAsset')) {
|
} else if (has(terms, 'updateAsset')) {
|
||||||
return t('Update asset proposal');
|
return t('Update asset proposal');
|
||||||
} else if (has(terms, 'newMarket')) {
|
} else if (has(terms, 'newMarket')) {
|
||||||
return t('New market proposal');
|
if (terms?.newMarket?.changes?.successor) {
|
||||||
|
return t('Successor market proposal');
|
||||||
|
} else {
|
||||||
|
return t('New market proposal');
|
||||||
|
}
|
||||||
} else if (has(terms, 'updateMarket')) {
|
} else if (has(terms, 'updateMarket')) {
|
||||||
return t('Update market proposal');
|
return t('Update market proposal');
|
||||||
} else if (has(terms, 'updateNetworkParameter')) {
|
} else if (has(terms, 'updateNetworkParameter')) {
|
||||||
@@ -85,6 +91,13 @@ export const TxProposal = ({ txData, pubKey, blockData }: TxProposalProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tx = proposal.terms?.newAsset || proposal.terms?.updateAsset;
|
const tx = proposal.terms?.newAsset || proposal.terms?.updateAsset;
|
||||||
|
const isSuccessorMarketProposal =
|
||||||
|
proposal?.terms?.newMarket?.changes?.successor;
|
||||||
|
const parentMarketId =
|
||||||
|
isSuccessorMarketProposal &&
|
||||||
|
proposal?.terms.newMarket?.changes?.successor?.parentMarketId;
|
||||||
|
const insurancePoolFraction =
|
||||||
|
proposal?.terms?.newMarket?.changes?.successor?.insurancePoolFraction;
|
||||||
|
|
||||||
// This component is not rendered if no bundle is required
|
// This component is not rendered if no bundle is required
|
||||||
const SignatureBundleComponent = proposal.terms?.newAsset
|
const SignatureBundleComponent = proposal.terms?.newAsset
|
||||||
@@ -111,6 +124,30 @@ export const TxProposal = ({ txData, pubKey, blockData }: TxProposalProps) => {
|
|||||||
<Hash text={deterministicId} />
|
<Hash text={deterministicId} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
{isSuccessorMarketProposal ? (
|
||||||
|
<>
|
||||||
|
{parentMarketId ? (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Previous market')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<MarketLink
|
||||||
|
id={
|
||||||
|
proposal.terms?.newMarket.changes.successor.parentMarketId
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : null}
|
||||||
|
{insurancePoolFraction ? (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Insurance pool fraction')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{formatNumber(Number(insurancePoolFraction) * 100, 0)}%
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</TableWithTbody>
|
</TableWithTbody>
|
||||||
<ProposalSummary
|
<ProposalSummary
|
||||||
id={deterministicId}
|
id={deterministicId}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import { MarketLink } from '../../links/';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import { CancelSummary } from '../../order-summary/order-cancellation';
|
||||||
|
import Hash from '../../links/hash';
|
||||||
|
import type { components } from '../../../../types/explorer';
|
||||||
|
|
||||||
|
export type StopOrderCancellationTransaction =
|
||||||
|
components['schemas']['v1StopOrdersCancellation'];
|
||||||
|
|
||||||
|
interface TxDetailsStopOrderCancelProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Someone cancelled a stop order
|
||||||
|
*/
|
||||||
|
export const TxDetailsStopOrderCancel = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsStopOrderCancelProps) => {
|
||||||
|
if (!txData || !txData.command) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const command: StopOrderCancellationTransaction =
|
||||||
|
txData.command.stopOrdersCancellation;
|
||||||
|
|
||||||
|
const { marketId, stopOrderId } = command;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Cancel stop order')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{stopOrderId ? (
|
||||||
|
<Hash text={stopOrderId} />
|
||||||
|
) : (
|
||||||
|
<CancelSummary orderId={stopOrderId} marketId={marketId} />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
{marketId ? (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Market')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<MarketLink id={marketId} />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : null}
|
||||||
|
</TableWithTbody>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import { MarketLink } from '../../links/';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import {
|
||||||
|
getStopOrderIds,
|
||||||
|
stopOrdersSignatureToDeterministicId,
|
||||||
|
} from '../lib/deterministic-ids';
|
||||||
|
import type { components } from '../../../../types/explorer';
|
||||||
|
import { StopOrderSetup } from './order/stop-order-setup';
|
||||||
|
|
||||||
|
type StopOrderSetup = components['schemas']['v1StopOrderSetup'];
|
||||||
|
|
||||||
|
interface TxDetailsOrderProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStopTypeLabel(
|
||||||
|
risesAbove: StopOrderSetup | undefined,
|
||||||
|
fallsBelow: StopOrderSetup | undefined
|
||||||
|
): string {
|
||||||
|
if (risesAbove && fallsBelow) {
|
||||||
|
return t('OCO (One Cancels Other)');
|
||||||
|
} else if (fallsBelow) {
|
||||||
|
return t('Falls Below ↘');
|
||||||
|
} else if (risesAbove) {
|
||||||
|
return t('Rises Above ↗');
|
||||||
|
} else {
|
||||||
|
return t('Stop Order');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StopMarketIdProps {
|
||||||
|
risesAbove: StopOrderSetup | undefined;
|
||||||
|
fallsBelow: StopOrderSetup | undefined;
|
||||||
|
showMarketName?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StopMarketId({
|
||||||
|
risesAbove,
|
||||||
|
fallsBelow,
|
||||||
|
showMarketName = false,
|
||||||
|
}: StopMarketIdProps) {
|
||||||
|
const raMarketId = risesAbove?.orderSubmission?.marketId;
|
||||||
|
const fbMarketId = fallsBelow?.orderSubmission?.marketId;
|
||||||
|
|
||||||
|
if (raMarketId && fbMarketId) {
|
||||||
|
if (raMarketId === fbMarketId) {
|
||||||
|
return <MarketLink id={raMarketId} showMarketName={showMarketName} />;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MarketLink id={raMarketId} showMarketName={showMarketName} />,
|
||||||
|
<MarketLink id={fbMarketId} showMarketName={showMarketName} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (raMarketId) {
|
||||||
|
return <MarketLink id={raMarketId} showMarketName={showMarketName} />;
|
||||||
|
} else if (fbMarketId) {
|
||||||
|
return <MarketLink id={fbMarketId} showMarketName={showMarketName} />;
|
||||||
|
} else {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export const TxDetailsStopOrderSubmission = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsOrderProps) => {
|
||||||
|
if (!txData || !txData.command.stopOrdersSubmission) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tx: components['schemas']['v1StopOrdersSubmission'] =
|
||||||
|
txData.command.stopOrdersSubmission;
|
||||||
|
|
||||||
|
const orderIds = stopOrdersSignatureToDeterministicId(
|
||||||
|
txData?.signature?.value
|
||||||
|
);
|
||||||
|
|
||||||
|
const { risesAboveId, fallsBelowId } = getStopOrderIds(
|
||||||
|
orderIds,
|
||||||
|
tx.risesAbove,
|
||||||
|
tx.fallsBelow
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared
|
||||||
|
txData={txData}
|
||||||
|
pubKey={pubKey}
|
||||||
|
blockData={blockData}
|
||||||
|
/>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Market ID')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<StopMarketId
|
||||||
|
risesAbove={tx.risesAbove}
|
||||||
|
fallsBelow={tx.fallsBelow}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Market')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<StopMarketId
|
||||||
|
risesAbove={tx.risesAbove}
|
||||||
|
fallsBelow={tx.fallsBelow}
|
||||||
|
showMarketName={true}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Trigger')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{getStopTypeLabel(tx.risesAbove, tx.fallsBelow)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableWithTbody>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
{tx.fallsBelow && fallsBelowId && (
|
||||||
|
<StopOrderSetup
|
||||||
|
type={'FallsBelow'}
|
||||||
|
{...tx.fallsBelow}
|
||||||
|
deterministicId={fallsBelowId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tx.risesAbove && risesAboveId && (
|
||||||
|
<StopOrderSetup
|
||||||
|
type={'RisesAbove'}
|
||||||
|
{...tx.risesAbove}
|
||||||
|
deterministicId={risesAboveId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
import { hexToString, txSignatureToDeterministicId } from './deterministic-ids';
|
import {
|
||||||
|
hexToString,
|
||||||
|
txSignatureToDeterministicId,
|
||||||
|
stopOrdersSignatureToDeterministicId,
|
||||||
|
} from './deterministic-ids';
|
||||||
|
|
||||||
it('txSignatureToDeterministicId Turns a known signature in to a known deterministic ID', () => {
|
it('txSignatureToDeterministicId Turns a known signature in to a known deterministic ID', () => {
|
||||||
const signature =
|
const signature =
|
||||||
@@ -20,3 +24,24 @@ it('hexToString encodes a known good value as bytes', () => {
|
|||||||
const res = hexToString(hex);
|
const res = hexToString(hex);
|
||||||
expect(res).toEqual([14, 221]);
|
expect(res).toEqual([14, 221]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('stopOrdersSignatureToDeterministicId', () => {
|
||||||
|
it('should return empty object if no signature is provided', () => {
|
||||||
|
const result = stopOrdersSignatureToDeterministicId();
|
||||||
|
expect(result.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return valid deterministic ids if a signature is provided', () => {
|
||||||
|
const signature = 'deadb33f';
|
||||||
|
const result = stopOrdersSignatureToDeterministicId(signature);
|
||||||
|
|
||||||
|
expect(result.length).toEqual(2);
|
||||||
|
|
||||||
|
expect(result[0]).toBe(
|
||||||
|
'4c45b67a8c08cbf1982883a75beaf309bf172461d04bd427623d6cd3d9ab0e91'
|
||||||
|
);
|
||||||
|
expect(result[1]).toBe(
|
||||||
|
'afe7509ff90d8f26339a0ab81e4d3e1fb6c4d44e94419aa5e13ae7659d894da1'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
import type { components } from '../../../../types/explorer';
|
||||||
import { sha3_256 } from 'js-sha3';
|
import { sha3_256 } from 'js-sha3';
|
||||||
|
type StopOrderSetup = components['schemas']['v1StopOrderSetup'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes a string as bytes
|
* Encodes a string as bytes
|
||||||
@@ -37,3 +39,58 @@ export function txSignatureToDeterministicId(signature: string): string {
|
|||||||
|
|
||||||
return hash.hex();
|
return hash.hex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a stop order signature string, returns the deterministic IDs of both potential
|
||||||
|
* Stop Orders. A stop order is not an order per se, but a trigger for an order. The order
|
||||||
|
* created by the stop order will have another ID based on the market event that hit the
|
||||||
|
* trigger, and as such is not deterministic.
|
||||||
|
*
|
||||||
|
* @param signature
|
||||||
|
* @returns string[]
|
||||||
|
*/
|
||||||
|
export function stopOrdersSignatureToDeterministicId(
|
||||||
|
signature?: string
|
||||||
|
): string[] {
|
||||||
|
if (!signature) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstId = txSignatureToDeterministicId(signature);
|
||||||
|
return [firstId, txSignatureToDeterministicId(firstId)];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type stopSignatures = {
|
||||||
|
risesAboveId: string | undefined;
|
||||||
|
fallsBelowId: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In 0.72.10 the way stop order IDs are determined is a little tricky. It will be stabilised
|
||||||
|
* in a future release.
|
||||||
|
* @param deterministicIds Output of stopORdersSignatureToDeterministicId
|
||||||
|
* @param risesAbove Stop order setup
|
||||||
|
* @param fallsBelow Stop order setup
|
||||||
|
* @returns Object containing the deterministic IDs of the stop orders
|
||||||
|
*/
|
||||||
|
export function getStopOrderIds(
|
||||||
|
deterministicIds: string[],
|
||||||
|
risesAbove: StopOrderSetup | undefined,
|
||||||
|
fallsBelow: StopOrderSetup | undefined
|
||||||
|
) {
|
||||||
|
if (risesAbove && fallsBelow) {
|
||||||
|
return {
|
||||||
|
risesAboveId: deterministicIds[0],
|
||||||
|
fallsBelowId: deterministicIds[1],
|
||||||
|
};
|
||||||
|
} else if (!fallsBelow && risesAbove) {
|
||||||
|
return {
|
||||||
|
risesAboveId: deterministicIds[0],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
fallsBelowId: deterministicIds[0] || undefined,
|
||||||
|
risesAboveId: deterministicIds[1] || undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
DropdownMenuSubContent,
|
DropdownMenuSubContent,
|
||||||
Icon,
|
Icon,
|
||||||
Button,
|
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import type { Dispatch, SetStateAction } from 'react';
|
import type { Dispatch, SetStateAction } from 'react';
|
||||||
import { FilterLabel } from './tx-filter-label';
|
import { FilterLabel } from './tx-filter-label';
|
||||||
@@ -35,6 +34,8 @@ export type FilterOption =
|
|||||||
| 'Protocol Upgrade'
|
| 'Protocol Upgrade'
|
||||||
| 'Register new Node'
|
| 'Register new Node'
|
||||||
| 'State Variable Proposal'
|
| 'State Variable Proposal'
|
||||||
|
| 'Stop Orders Submission'
|
||||||
|
| 'Stop Orders Cancellation'
|
||||||
| 'Submit Oracle Data'
|
| 'Submit Oracle Data'
|
||||||
| 'Submit Order'
|
| 'Submit Order'
|
||||||
| 'Transfer Funds'
|
| 'Transfer Funds'
|
||||||
@@ -54,6 +55,8 @@ export const PrimaryFilterOptions: FilterOption[] = [
|
|||||||
'Delegate',
|
'Delegate',
|
||||||
'Liquidity Provision Order',
|
'Liquidity Provision Order',
|
||||||
'Proposal',
|
'Proposal',
|
||||||
|
'Stop Orders Submission',
|
||||||
|
'Stop Orders Cancellation',
|
||||||
'Submit Oracle Data',
|
'Submit Oracle Data',
|
||||||
'Submit Order',
|
'Submit Order',
|
||||||
'Transfer Funds',
|
'Transfer Funds',
|
||||||
@@ -100,15 +103,13 @@ export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
|
|||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
modal={false}
|
modal={false}
|
||||||
trigger={
|
trigger={
|
||||||
<DropdownMenuTrigger className="ml-0">
|
<DropdownMenuTrigger>
|
||||||
<Button size="xs" data-testid="filter-trigger">
|
<FilterLabel filters={filters} />
|
||||||
<FilterLabel filters={filters} />
|
|
||||||
</Button>
|
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
{filters.size > 0 ? null : (
|
{filters.size > 1 ? null : (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuCheckboxItem
|
<DropdownMenuCheckboxItem
|
||||||
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
|
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export const TxsListNavigation = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="xs"
|
||||||
disabled={!hasMoreTxs || loading}
|
disabled={!hasMoreTxs}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
nextPage();
|
nextPage();
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -50,6 +50,25 @@ const displayString: StringMap = {
|
|||||||
'Stop Orders Cancellation': 'Cancel stop',
|
'Stop Orders Cancellation': 'Cancel stop',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getLabelForStopOrderType(
|
||||||
|
orderType: string,
|
||||||
|
command: components['schemas']['v1InputData']
|
||||||
|
): string {
|
||||||
|
if (command.stopOrdersSubmission) {
|
||||||
|
if (
|
||||||
|
command.stopOrdersSubmission.risesAbove &&
|
||||||
|
command.stopOrdersSubmission.fallsBelow
|
||||||
|
) {
|
||||||
|
return 'Stop ⇅';
|
||||||
|
} else if (command.stopOrdersSubmission.risesAbove) {
|
||||||
|
return 'Stop ↗';
|
||||||
|
} else if (command.stopOrdersSubmission.fallsBelow) {
|
||||||
|
return 'Stop ↘';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'Stop';
|
||||||
|
}
|
||||||
|
|
||||||
export function getLabelForOrderType(
|
export function getLabelForOrderType(
|
||||||
orderType: string,
|
orderType: string,
|
||||||
command: components['schemas']['v1InputData']
|
command: components['schemas']['v1InputData']
|
||||||
@@ -78,7 +97,11 @@ export function getLabelForProposal(
|
|||||||
} else if (proposal.terms?.updateAsset) {
|
} else if (proposal.terms?.updateAsset) {
|
||||||
return t('Proposal: Update asset');
|
return t('Proposal: Update asset');
|
||||||
} else if (proposal.terms?.newMarket) {
|
} else if (proposal.terms?.newMarket) {
|
||||||
return t('Proposal: New market');
|
if (proposal.terms?.newMarket.changes?.successor) {
|
||||||
|
return t('Proposal: Successor market');
|
||||||
|
} else {
|
||||||
|
return t('Proposal: New market');
|
||||||
|
}
|
||||||
} else if (proposal.terms?.updateMarket) {
|
} else if (proposal.terms?.updateMarket) {
|
||||||
return t('Proposal: Update market');
|
return t('Proposal: Update market');
|
||||||
} else if (proposal.terms?.updateNetworkParameter) {
|
} else if (proposal.terms?.updateNetworkParameter) {
|
||||||
@@ -166,6 +189,7 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
|||||||
'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-250';
|
'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-250';
|
||||||
|
|
||||||
// This will get unwieldy and should probably produce a different colour of tag
|
// This will get unwieldy and should probably produce a different colour of tag
|
||||||
|
// Note that colours are currently arbitrary
|
||||||
if (type === 'Chain Event' && !!command?.chainEvent) {
|
if (type === 'Chain Event' && !!command?.chainEvent) {
|
||||||
type = getLabelForChainEvent(command.chainEvent);
|
type = getLabelForChainEvent(command.chainEvent);
|
||||||
colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink';
|
colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink';
|
||||||
@@ -177,6 +201,12 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
|||||||
type = getLabelForProposal(command.proposalSubmission);
|
type = getLabelForProposal(command.proposalSubmission);
|
||||||
}
|
}
|
||||||
colours = 'text-black bg-vega-yellow';
|
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';
|
||||||
|
} else if (type === 'Stop' && command) {
|
||||||
|
type = getLabelForStopOrderType(orderType, command);
|
||||||
|
colours = 'text-white dark-text-white bg-vega-blue dark:bg-vega-blue';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'Vote on Proposal') {
|
if (type === 'Vote on Proposal') {
|
||||||
|
|||||||
@@ -86,14 +86,18 @@ describe('Txs infinite list item', () => {
|
|||||||
render(
|
render(
|
||||||
<MockedProvider>
|
<MockedProvider>
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<TxsInfiniteListItem
|
<table>
|
||||||
type="testType"
|
<tbody>
|
||||||
submitter="testPubKey"
|
<TxsInfiniteListItem
|
||||||
hash="testTxHash"
|
type="testType"
|
||||||
block="1"
|
submitter="testPubKey"
|
||||||
code={0}
|
hash="testTxHash"
|
||||||
command={{}}
|
block="1"
|
||||||
/>
|
code={0}
|
||||||
|
command={{}}
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</MockedProvider>
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ const DEFAULT_TRUNCATE_LENGTH = 7;
|
|||||||
|
|
||||||
export function getIdTruncateLength(screen: Screen): number {
|
export function getIdTruncateLength(screen: Screen): number {
|
||||||
if (['xxxl', 'xxl'].includes(screen)) {
|
if (['xxxl', 'xxl'].includes(screen)) {
|
||||||
return 64;
|
|
||||||
} else if (['xl', 'lg', 'md'].includes(screen)) {
|
|
||||||
return 32;
|
return 32;
|
||||||
|
} else if (['xl', 'lg', 'md'].includes(screen)) {
|
||||||
|
return 16;
|
||||||
}
|
}
|
||||||
return DEFAULT_TRUNCATE_LENGTH;
|
return DEFAULT_TRUNCATE_LENGTH;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,17 @@ import type { BlockExplorerTransactionResult } from '../../routes/types/block-ex
|
|||||||
import { Side } from '@vegaprotocol/types';
|
import { Side } from '@vegaprotocol/types';
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
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[] => {
|
const generateTxs = (number: number): BlockExplorerTransactionResult[] => {
|
||||||
return Array.from(Array(number)).map((_) => ({
|
return Array.from(Array(number)).map((_) => ({
|
||||||
block: '87901',
|
block: '87901',
|
||||||
index: 2,
|
index: 2,
|
||||||
hash: '0F8B98DA0923A50786B852D9CA11E051CACC4C733E1DB93D535C7D81DBD10F6F',
|
hash: generateHash(),
|
||||||
submitter:
|
submitter:
|
||||||
'4b782482f587d291e8614219eb9a5ee9280fa2c58982dee71d976782a9be1964',
|
'4b782482f587d291e8614219eb9a5ee9280fa2c58982dee71d976782a9be1964',
|
||||||
type: 'Submit Order',
|
type: 'Submit Order',
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export const TxsInfiniteList = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="overflow-scroll">
|
<div>
|
||||||
<table className={className} data-testid="transactions-list">
|
<table className={className} data-testid="transactions-list">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="w-full mb-3 text-vega-dark-300 uppercase text-left">
|
<tr className="w-full mb-3 text-vega-dark-300 uppercase text-left">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Table, TableRow } from '../table';
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||||
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
|
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 { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit';
|
||||||
import EmptyList from '../empty-list/empty-list';
|
import EmptyList from '../empty-list/empty-list';
|
||||||
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||||
@@ -14,7 +14,7 @@ interface TxsPerBlockProps {
|
|||||||
|
|
||||||
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
||||||
const filters = `filters[block.height]=${blockHeight}`;
|
const filters = `filters[block.height]=${blockHeight}`;
|
||||||
const url = getTxsDataUrl({ limit: txCount.toString(), filters });
|
const url = getTxsDataUrl({ filters, count: txCount });
|
||||||
const {
|
const {
|
||||||
state: { data, loading, error },
|
state: { data, loading, error },
|
||||||
} = useFetch<BlockExplorerTransactions>(url);
|
} = useFetch<BlockExplorerTransactions>(url);
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ const windowOrDefault = (key: string) => {
|
|||||||
return (process.env[key] as string) || '';
|
return (process.env[key] as string) || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const truthy = ['1', 'true'];
|
|
||||||
|
|
||||||
export const ENV = {
|
export const ENV = {
|
||||||
// Data sources
|
// Data sources
|
||||||
// Environment
|
// Environment
|
||||||
@@ -20,19 +18,6 @@ export const ENV = {
|
|||||||
governanceUrl: windowOrDefault('NX_VEGA_GOVERNANCE_URL'),
|
governanceUrl: windowOrDefault('NX_VEGA_GOVERNANCE_URL'),
|
||||||
vegaRepoUrl: windowOrDefault('NX_VEGA_REPO_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: {
|
addresses: {
|
||||||
feedback: windowOrDefault('NX_GITHUB_FEEDBACK_URL'),
|
feedback: windowOrDefault('NX_GITHUB_FEEDBACK_URL'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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 { useFetch } from '@vegaprotocol/react-helpers';
|
||||||
import type {
|
import type {
|
||||||
BlockExplorerTransactionResult,
|
BlockExplorerTransactionResult,
|
||||||
BlockExplorerTransactions,
|
BlockExplorerTransactions,
|
||||||
} from '../routes/types/block-explorer-response';
|
} from '../routes/types/block-explorer-response';
|
||||||
import { DATA_SOURCES } from '../config';
|
|
||||||
import isNumber from 'lodash/isNumber';
|
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 {
|
export function getTypeFilters(filters?: Set<FilterOption>) {
|
||||||
txsData: BlockExplorerTransactionResult[];
|
if (!filters) {
|
||||||
hasMoreTxs: boolean;
|
return '';
|
||||||
cursor: string;
|
} else if (filters.size > 1) {
|
||||||
previousCursors: string[];
|
return '';
|
||||||
hasPreviousPage: boolean;
|
}
|
||||||
|
|
||||||
|
const forcedSingleFilter = Array.from(filters)[0];
|
||||||
|
return `filters[cmd.type]=${forcedSingleFilter}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUseTxsData {
|
export interface IUseTxsData {
|
||||||
limit: number;
|
count?: number;
|
||||||
filters?: string;
|
before?: string;
|
||||||
|
after?: string;
|
||||||
|
party?: string;
|
||||||
|
filters?: Set<FilterOption>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IGetTxsDataUrl {
|
export const useTxsData = ({
|
||||||
limit: string;
|
count = 25,
|
||||||
filters?: string;
|
before,
|
||||||
}
|
after,
|
||||||
|
filters,
|
||||||
|
party,
|
||||||
|
}: IUseTxsData) => {
|
||||||
|
const [, setSearchParams] = useSearchParams();
|
||||||
|
let hasMoreTxs = true;
|
||||||
|
let txsData: BlockExplorerTransactionResult[] = [];
|
||||||
|
|
||||||
export const getTxsDataUrl = ({ limit, filters }: IGetTxsDataUrl) => {
|
const url = getTxsDataUrl({
|
||||||
const url = new URL(`${DATA_SOURCES.blockExplorerUrl}/transactions`);
|
filters: getTypeFilters(filters),
|
||||||
|
count,
|
||||||
if (limit) {
|
before,
|
||||||
url.searchParams.append('limit', limit);
|
after,
|
||||||
}
|
party,
|
||||||
|
|
||||||
// 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({ limit: limit.toString(), filters });
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
state: { data, error, loading },
|
state: { data, error, loading },
|
||||||
refetch,
|
refetch,
|
||||||
} = useFetch<BlockExplorerTransactions>(url, {}, true);
|
} = useFetch<BlockExplorerTransactions>(url, {}, true);
|
||||||
|
|
||||||
useEffect(() => {
|
if (!loading && data && isNumber(data.transactions.length)) {
|
||||||
if (!loading && data && isNumber(data.transactions.length)) {
|
hasMoreTxs = data.transactions.length >= count;
|
||||||
setTxsState((prev) => {
|
txsData = data.transactions;
|
||||||
return {
|
}
|
||||||
...prev,
|
|
||||||
txsData: data.transactions,
|
|
||||||
hasMoreTxs: data.transactions.length >= limit,
|
|
||||||
cursor: data?.transactions.at(-1)?.cursor || '',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [loading, setTxsState, data, limit]);
|
|
||||||
|
|
||||||
const nextPage = useCallback(() => {
|
const nextPage = useCallback(() => {
|
||||||
const c = data?.transactions.at(0)?.cursor;
|
const after = data?.transactions.at(-1)?.cursor || '';
|
||||||
const newPreviousCursors = c ? [...previousCursors, c] : previousCursors;
|
const params: URLSearchParamsInit = { after };
|
||||||
|
if (filters) {
|
||||||
setTxsState((prev) => ({
|
params.filters = Array.from(filters).join(',');
|
||||||
...prev,
|
}
|
||||||
hasPreviousPage: true,
|
setSearchParams(params);
|
||||||
previousCursors: newPreviousCursors,
|
}, [filters, data, setSearchParams]);
|
||||||
}));
|
|
||||||
|
|
||||||
return refetch({
|
|
||||||
limit,
|
|
||||||
before: cursor,
|
|
||||||
});
|
|
||||||
}, [data, previousCursors, cursor, limit, refetch]);
|
|
||||||
|
|
||||||
const previousPage = useCallback(() => {
|
const previousPage = useCallback(() => {
|
||||||
const previousCursor = [...previousCursors].pop();
|
const before = data?.transactions[0]?.cursor || '';
|
||||||
const newPreviousCursors = previousCursors.slice(0, -1);
|
const params: URLSearchParamsInit = { before };
|
||||||
setTxsState((prev) => ({
|
if (filters && filters.size > 0 && filters.size === 1) {
|
||||||
...prev,
|
params.filters = Array.from(filters)[0];
|
||||||
hasPreviousPage: newPreviousCursors.length > 0,
|
}
|
||||||
previousCursors: newPreviousCursors,
|
setSearchParams(params);
|
||||||
}));
|
}, [filters, data, setSearchParams]);
|
||||||
return refetch({
|
|
||||||
limit,
|
|
||||||
before: previousCursor,
|
|
||||||
});
|
|
||||||
}, [previousCursors, limit, refetch]);
|
|
||||||
|
|
||||||
const refreshTxs = useCallback(async () => {
|
const refreshTxs = useCallback(async () => {
|
||||||
setTxsState(() => ({
|
const params: URLSearchParamsInit = {};
|
||||||
txsData: [],
|
if (filters && filters.size > 0 && filters.size === 1) {
|
||||||
cursor: '',
|
params.filters = Array.from(filters)[0];
|
||||||
previousCursors: [],
|
}
|
||||||
hasMoreTxs: false,
|
setSearchParams(params);
|
||||||
hasPreviousPage: false,
|
|
||||||
}));
|
|
||||||
|
|
||||||
refetch({ limit });
|
refetch({ count: BE_TXS_PER_REQUEST });
|
||||||
}, [setTxsState, limit, refetch, filters]); // eslint-disable-line react-hooks/exhaustive-deps
|
}, [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 {
|
return {
|
||||||
|
updateFilters,
|
||||||
txsData,
|
txsData,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
hasMoreTxs,
|
hasMoreTxs,
|
||||||
hasPreviousPage,
|
|
||||||
previousCursors,
|
|
||||||
cursor,
|
|
||||||
refreshTxs,
|
refreshTxs,
|
||||||
nextPage,
|
nextPage,
|
||||||
previousPage,
|
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({
|
(useFetch as jest.Mock).mockReturnValue({
|
||||||
state: { data: createBlockResponse(1), loading: false, error: null },
|
state: { data: createBlockResponse(1), loading: false, error: null },
|
||||||
});
|
});
|
||||||
|
|
||||||
render(renderComponent(1));
|
render(renderComponent(1));
|
||||||
await waitFor(() => screen.getByTestId('block-header'));
|
await waitFor(() => screen.getByTestId('block-header'));
|
||||||
expect(screen.getByTestId('previous-block-button')).toHaveAttribute(
|
expect(screen.getByTestId('previous-block-button')).toHaveAttribute(
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ import { Footer } from '../components/footer/footer';
|
|||||||
import { Header } from '../components/header';
|
import { Header } from '../components/header';
|
||||||
import { Routes } from './route-names';
|
import { Routes } from './route-names';
|
||||||
import { useExplorerNodeNamesLazyQuery } from './validators/__generated__/NodeNames';
|
import { useExplorerNodeNamesLazyQuery } from './validators/__generated__/NodeNames';
|
||||||
|
import {
|
||||||
|
ProtocolUpgradeCountdownMode,
|
||||||
|
ProtocolUpgradeInProgressNotification,
|
||||||
|
ProtocolUpgradeProposalNotification,
|
||||||
|
} from '@vegaprotocol/proposals';
|
||||||
|
|
||||||
const DialogsContainer = () => {
|
const DialogsContainer = () => {
|
||||||
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
|
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
|
||||||
@@ -62,6 +67,10 @@ export const Layout = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Header />
|
<Header />
|
||||||
|
<ProtocolUpgradeProposalNotification
|
||||||
|
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
|
||||||
|
/>
|
||||||
|
<ProtocolUpgradeInProgressNotification />
|
||||||
</div>
|
</div>
|
||||||
<div className={fixedWidthClasses}>
|
<div className={fixedWidthClasses}>
|
||||||
<main className="p-4">
|
<main className="p-4">
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
export * from './network-parameters';
|
export * from './network-parameters';
|
||||||
|
export * from './structure-network-params';
|
||||||
|
|||||||
@@ -1,82 +1,105 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
|
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
|
||||||
import { NetworkParametersTable } from './network-parameters';
|
import { NetworkParametersTable } from './network-parameters';
|
||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
const renderComponent = (data: NetworkParamsQuery | undefined) => {
|
||||||
|
return render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<NetworkParametersTable data={data} loading={false} />
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
networkParametersConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'spam.protection.delegation.min.tokens',
|
||||||
|
value: '3',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'spam.protection.voting.min.tokens',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'reward.staking.delegation.minimumValidatorStake',
|
||||||
|
value: '2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'reward.asset',
|
||||||
|
value:
|
||||||
|
'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
describe('NetworkParametersTable', () => {
|
describe('NetworkParametersTable', () => {
|
||||||
it('renders correctly when it has network params', () => {
|
it('renders headers correctly', () => {
|
||||||
const data: NetworkParamsQuery = {
|
renderComponent(mockData);
|
||||||
networkParametersConnection: {
|
|
||||||
edges: [
|
const allHeadings = screen.getAllByRole('heading');
|
||||||
{
|
expect(
|
||||||
node: {
|
allHeadings.map((h) => {
|
||||||
__typename: 'NetworkParameter',
|
return {
|
||||||
key: 'market.liquidityProvision.minLpStakeQuantumMultiple',
|
text: h.textContent,
|
||||||
value: '1',
|
level: h.tagName,
|
||||||
},
|
testId: h.getAttribute('data-testid'),
|
||||||
},
|
};
|
||||||
{
|
})
|
||||||
node: {
|
).toEqual([
|
||||||
__typename: 'NetworkParameter',
|
{
|
||||||
key: 'market.fee.factors.infrastructureFee',
|
text: 'Network Parameters',
|
||||||
value: '0.0005',
|
level: 'H1',
|
||||||
},
|
testId: 'network-param-header',
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
};
|
{ text: 'Spam', level: 'H1', testId: 'spam' },
|
||||||
render(<NetworkParametersTable data={data} loading={false} />);
|
{ text: 'Protection', level: 'H2', testId: 'spam-protection' },
|
||||||
expect(screen.getByTestId('network-param-header')).toHaveTextContent(
|
{ text: 'Delegation', level: 'H3', testId: 'spam-protection-delegation' },
|
||||||
'Network Parameters'
|
{ text: 'Min', level: 'H4', testId: 'spam-protection-delegation-min' },
|
||||||
);
|
{ text: 'Voting', level: 'H3', testId: 'spam-protection-voting' },
|
||||||
const rows = screen.getAllByTestId('key-value-table-row');
|
{ text: 'Min', level: 'H4', testId: 'spam-protection-voting-min' },
|
||||||
expect(rows[0].children[0]).toHaveTextContent(
|
{ text: 'Reward', level: 'H1', testId: 'reward' },
|
||||||
'market.fee.factors.infrastructureFee'
|
{ text: 'Staking', level: 'H2', testId: 'reward-staking' },
|
||||||
);
|
{ text: 'Delegation', level: 'H3', testId: 'reward-staking-delegation' },
|
||||||
expect(rows[1].children[0]).toHaveTextContent(
|
]);
|
||||||
'market.liquidityProvision.minLpStakeQuantumMultiple'
|
|
||||||
);
|
|
||||||
expect(rows[0].children[1]).toHaveTextContent('0.0005');
|
|
||||||
expect(rows[1].children[1]).toHaveTextContent('1');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the rows in ascending order', () => {
|
it('renders network params correctly', () => {
|
||||||
const data: NetworkParamsQuery = {
|
renderComponent(mockData);
|
||||||
networkParametersConnection: {
|
|
||||||
edges: [
|
const delegationMinTokensRow = screen.getByTestId(
|
||||||
{
|
'spam-protection-delegation-min-tokens'
|
||||||
node: {
|
|
||||||
__typename: 'NetworkParameter',
|
|
||||||
key: 'market.fee.factors.infrastructureFee',
|
|
||||||
value: '0.0005',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
__typename: 'NetworkParameter',
|
|
||||||
key: 'market.liquidityProvision.minLpStakeQuantumMultiple',
|
|
||||||
value: '1',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
render(<NetworkParametersTable data={data} loading={false} />);
|
|
||||||
expect(screen.getByTestId('network-param-header')).toHaveTextContent(
|
|
||||||
'Network Parameters'
|
|
||||||
);
|
);
|
||||||
const rows = screen.getAllByTestId('key-value-table-row');
|
expect(delegationMinTokensRow).toHaveTextContent('0.000000000000000003');
|
||||||
expect(rows[0].children[0]).toHaveTextContent(
|
|
||||||
'market.fee.factors.infrastructureFee'
|
const votingMinTokensRow = screen.getByTestId(
|
||||||
|
'spam-protection-voting-min-tokens'
|
||||||
);
|
);
|
||||||
expect(rows[1].children[0]).toHaveTextContent(
|
expect(votingMinTokensRow).toHaveTextContent('0.000000000000000001');
|
||||||
'market.liquidityProvision.minLpStakeQuantumMultiple'
|
|
||||||
|
const minimumValidatorStakeRow = screen.getByTestId(
|
||||||
|
'reward-staking-delegation-minimumValidatorStake'
|
||||||
|
);
|
||||||
|
expect(minimumValidatorStakeRow).toHaveTextContent('2');
|
||||||
|
|
||||||
|
const assetRow = screen.getByTestId('reward-asset');
|
||||||
|
expect(assetRow).toHaveTextContent(
|
||||||
|
'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55'
|
||||||
);
|
);
|
||||||
expect(rows[0].children[1]).toHaveTextContent('0.0005');
|
|
||||||
expect(rows[1].children[1]).toHaveTextContent('1');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not render rows when is loading', () => {
|
it('does not render rows when is loading', () => {
|
||||||
render(<NetworkParametersTable data={undefined} loading={true} />);
|
renderComponent(undefined);
|
||||||
expect(screen.getByTestId('network-param-header')).toHaveTextContent(
|
expect(screen.getByTestId('network-param-header')).toHaveTextContent(
|
||||||
'Network Parameters'
|
'Network Parameters'
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import startCase from 'lodash/startCase';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
AsyncRenderer,
|
AsyncRenderer,
|
||||||
KeyValueTable,
|
|
||||||
KeyValueTableRow,
|
KeyValueTableRow,
|
||||||
SyntaxHighlighter,
|
SyntaxHighlighter,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
@@ -12,11 +14,12 @@ import {
|
|||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { RouteTitle } from '../../components/route-title';
|
import { RouteTitle } from '../../components/route-title';
|
||||||
import orderBy from 'lodash/orderBy';
|
|
||||||
import { useNetworkParamsQuery } from '@vegaprotocol/network-parameters';
|
import { useNetworkParamsQuery } from '@vegaprotocol/network-parameters';
|
||||||
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
|
|
||||||
import { useScrollToLocation } from '../../hooks/scroll-to-location';
|
import { useScrollToLocation } from '../../hooks/scroll-to-location';
|
||||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||||
|
import { structureNetworkParams } from './structure-network-params';
|
||||||
|
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
|
||||||
|
import type { GroupedParams } from './structure-network-params';
|
||||||
|
|
||||||
const PERCENTAGE_PARAMS = [
|
const PERCENTAGE_PARAMS = [
|
||||||
'governance.proposal.asset.requiredMajority',
|
'governance.proposal.asset.requiredMajority',
|
||||||
@@ -58,6 +61,54 @@ const BIG_NUMBER_PARAMS = [
|
|||||||
'governance.proposal.updateAsset.minVoterBalance',
|
'governance.proposal.updateAsset.minVoterBalance',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const renderGroupedParams = (
|
||||||
|
group: GroupedParams,
|
||||||
|
level: number,
|
||||||
|
parentKeys: string[] = []
|
||||||
|
) => {
|
||||||
|
const Header = `h${level}` as keyof JSX.IntrinsicElements;
|
||||||
|
const headerStyles = classNames('uppercase font-semibold', {
|
||||||
|
'pt-6 text-3xl underline': level === 1,
|
||||||
|
'pt-3 text-2xl': level === 2,
|
||||||
|
'pt-2 text-lg': level === 3,
|
||||||
|
'pt-2 text-default': level === 4,
|
||||||
|
});
|
||||||
|
|
||||||
|
return Object.entries(group).map(([key, value]) => {
|
||||||
|
const fullPath = [...parentKeys, key].join('.');
|
||||||
|
const isLeafNode = typeof value !== 'object';
|
||||||
|
const id = parentKeys.concat([key]).join('-');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={key}>
|
||||||
|
{!isLeafNode && (
|
||||||
|
<div id={id}>
|
||||||
|
<Link to={`#${id}`}>
|
||||||
|
<Header className={headerStyles} data-testid={id}>
|
||||||
|
{startCase(key)}
|
||||||
|
</Header>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isLeafNode ? (
|
||||||
|
typeof value === 'string' ? (
|
||||||
|
<div data-testid={id}>
|
||||||
|
<NetworkParameterRow
|
||||||
|
key={fullPath}
|
||||||
|
row={{ key: fullPath, value: value }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : null
|
||||||
|
) : (
|
||||||
|
<div className="pb-1">
|
||||||
|
{renderGroupedParams(value, level + 1, [...parentKeys, key])}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const NetworkParameterRow = ({
|
export const NetworkParameterRow = ({
|
||||||
row: { key, value },
|
row: { key, value },
|
||||||
}: {
|
}: {
|
||||||
@@ -77,7 +128,9 @@ export const NetworkParameterRow = ({
|
|||||||
>
|
>
|
||||||
{key}
|
{key}
|
||||||
{isSyntaxRow ? (
|
{isSyntaxRow ? (
|
||||||
<SyntaxHighlighter data={JSON.parse(value)} />
|
<div className="pb-2">
|
||||||
|
<SyntaxHighlighter data={JSON.parse(value)} />
|
||||||
|
</div>
|
||||||
) : isNaN(Number(value)) ? (
|
) : isNaN(Number(value)) ? (
|
||||||
value
|
value
|
||||||
) : BIG_NUMBER_PARAMS.includes(key) ? (
|
) : BIG_NUMBER_PARAMS.includes(key) ? (
|
||||||
@@ -113,17 +166,12 @@ export const NetworkParametersTable = ({
|
|||||||
loading={loading}
|
loading={loading}
|
||||||
error={error}
|
error={error}
|
||||||
render={(data) => {
|
render={(data) => {
|
||||||
const ascParams = orderBy(
|
const flatParams = removePaginationWrapper(
|
||||||
removePaginationWrapper(data.networkParametersConnection.edges),
|
data.networkParametersConnection.edges
|
||||||
(param) => param.key,
|
|
||||||
'asc'
|
|
||||||
);
|
);
|
||||||
|
const groupedParams = structureNetworkParams(flatParams);
|
||||||
return (
|
return (
|
||||||
<KeyValueTable data-testid="parameters">
|
<div className="-mt-6">{renderGroupedParams(groupedParams, 1)}</div>
|
||||||
{(ascParams || []).map((row) => (
|
|
||||||
<NetworkParameterRow key={row.key} row={row} />
|
|
||||||
))}
|
|
||||||
</KeyValueTable>
|
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
import type { GroupedParams } from './structure-network-params';
|
||||||
|
import {
|
||||||
|
structureParams,
|
||||||
|
sortGroupedParams,
|
||||||
|
structureNetworkParams,
|
||||||
|
} from './structure-network-params';
|
||||||
|
|
||||||
|
describe('structureParams', () => {
|
||||||
|
it('should correctly structure params', () => {
|
||||||
|
const input = [
|
||||||
|
{ key: 'spam.protection.delegation.min.tokens', value: '10' },
|
||||||
|
{ key: 'spam.protection.voting.min.tokens', value: '5' },
|
||||||
|
];
|
||||||
|
const output: GroupedParams = {
|
||||||
|
spam: {
|
||||||
|
protection: {
|
||||||
|
delegation: {
|
||||||
|
min: {
|
||||||
|
tokens: '10',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
voting: {
|
||||||
|
min: {
|
||||||
|
tokens: '5',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(structureParams(input)).toEqual(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle top-level keys correctly', () => {
|
||||||
|
const input = [{ key: 'levelOne', value: '10' }];
|
||||||
|
const output = {
|
||||||
|
levelOne: '10',
|
||||||
|
};
|
||||||
|
expect(structureParams(input)).toEqual(output);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sortGroupedParams', () => {
|
||||||
|
it('should correctly sort grouped params', () => {
|
||||||
|
const input: GroupedParams = {
|
||||||
|
spam: {
|
||||||
|
protection: {
|
||||||
|
delegation: {
|
||||||
|
min: {
|
||||||
|
tokens: '10',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
reward: '50',
|
||||||
|
};
|
||||||
|
const output: GroupedParams = {
|
||||||
|
reward: '50',
|
||||||
|
spam: {
|
||||||
|
protection: {
|
||||||
|
delegation: {
|
||||||
|
min: {
|
||||||
|
tokens: '10',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(sortGroupedParams(input)).toEqual(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle already sorted keys', () => {
|
||||||
|
const input = {
|
||||||
|
a: '10',
|
||||||
|
b: {
|
||||||
|
c: '5',
|
||||||
|
d: '6',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(sortGroupedParams(input)).toEqual(input);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('structureNetworkParams', () => {
|
||||||
|
it('should structure and sort network params correctly', () => {
|
||||||
|
const input = [
|
||||||
|
{ key: 'spam.protection.delegation.min.tokens', value: '10' },
|
||||||
|
{ key: 'reward.asset', value: '50' },
|
||||||
|
];
|
||||||
|
const output: GroupedParams = {
|
||||||
|
reward: {
|
||||||
|
asset: '50',
|
||||||
|
},
|
||||||
|
spam: {
|
||||||
|
protection: {
|
||||||
|
delegation: {
|
||||||
|
min: {
|
||||||
|
tokens: '10',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(structureNetworkParams(input)).toEqual(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an empty object if no params are provided', () => {
|
||||||
|
expect(structureNetworkParams([])).toEqual({});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* Categorizes and sorts an array of key-value pairs of network params into a nested object structure.
|
||||||
|
*
|
||||||
|
* The function takes an array of network params where keys are dot-delimited
|
||||||
|
* strings representing nested categories (e.g., 'spam.protection.delegation.min.tokens').
|
||||||
|
*
|
||||||
|
* Why this is necessary:
|
||||||
|
* A flat key-value structure wouldn't provide the hierarchical information needed.
|
||||||
|
* Organizing network parameters like this allows the rendering of nested headers
|
||||||
|
* and their corresponding network params.
|
||||||
|
*
|
||||||
|
* It also ensures that items with the minimum amount of nesting are ordered first. This
|
||||||
|
* allows us to render these items first, before more deeply nested items are rendered with
|
||||||
|
* subheaders. This creates a more intuitive UI.
|
||||||
|
*
|
||||||
|
* For example, given the input:
|
||||||
|
* [
|
||||||
|
* { key: 'spam.protection.delegation.min.tokens', value: '10' },
|
||||||
|
* { key: 'spam.protection.voting.min.tokens', value: '5' },
|
||||||
|
* { key: 'reward.staking.delegation.minimumValidatorStake', value: '2' }
|
||||||
|
* { key: 'reward.asset', value: 'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55' }
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* The output will be:
|
||||||
|
* {
|
||||||
|
* spam: {
|
||||||
|
* protection: {
|
||||||
|
* delegation: {
|
||||||
|
* min: {
|
||||||
|
* tokens: '10'
|
||||||
|
* }
|
||||||
|
* },
|
||||||
|
* voting: {
|
||||||
|
* min: {
|
||||||
|
* tokens: '5'
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* },
|
||||||
|
* reward: {
|
||||||
|
* asset: 'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55',
|
||||||
|
* staking: {
|
||||||
|
* delegation: {
|
||||||
|
* minimumValidatorStake: '2'
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param {Array} params - An array of key-value pairs to categorize and sort.
|
||||||
|
* @returns {GroupedParams} - A nested object that groups the key-value pairs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type GroupedParams = {
|
||||||
|
[key: string]: string | GroupedParams;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const structureParams = (
|
||||||
|
params: { key: string; value: string }[]
|
||||||
|
): GroupedParams => {
|
||||||
|
const grouped: GroupedParams = {};
|
||||||
|
|
||||||
|
params.forEach(({ key, value }) => {
|
||||||
|
const parts = key.split('.');
|
||||||
|
let node: GroupedParams = grouped;
|
||||||
|
|
||||||
|
parts.forEach((part, i) => {
|
||||||
|
if (typeof node[part] === 'undefined') {
|
||||||
|
node[part] = i === parts.length - 1 ? value : {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof node[part] === 'object') {
|
||||||
|
node = node[part] as GroupedParams;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return grouped;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortGroupedParams = (
|
||||||
|
groupedParams: GroupedParams
|
||||||
|
): GroupedParams => {
|
||||||
|
const sorted: GroupedParams = {};
|
||||||
|
|
||||||
|
// Sort top-level keys first
|
||||||
|
Object.entries(groupedParams).forEach(([key, value]) => {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
sorted[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.entries(groupedParams).forEach(([key, value]) => {
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
sorted[key] = sortGroupedParams(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return sorted;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const structureNetworkParams = (
|
||||||
|
params: { key: string; value: string }[]
|
||||||
|
) => {
|
||||||
|
const grouped = structureParams(params);
|
||||||
|
return sortGroupedParams(grouped);
|
||||||
|
};
|
||||||
@@ -1,59 +1,5 @@
|
|||||||
fragment ExplorerOracleDataSource on OracleSpec {
|
|
||||||
dataSourceSpec {
|
|
||||||
spec {
|
|
||||||
id
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
status
|
|
||||||
data {
|
|
||||||
sourceType {
|
|
||||||
... on DataSourceDefinitionInternal {
|
|
||||||
sourceType {
|
|
||||||
... on DataSourceSpecConfigurationTime {
|
|
||||||
conditions {
|
|
||||||
value
|
|
||||||
operator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
... on DataSourceDefinitionExternal {
|
|
||||||
sourceType {
|
|
||||||
... on DataSourceSpecConfiguration {
|
|
||||||
signers {
|
|
||||||
signer {
|
|
||||||
... on ETHAddress {
|
|
||||||
address
|
|
||||||
}
|
|
||||||
... on PubKey {
|
|
||||||
key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filters {
|
|
||||||
key {
|
|
||||||
name
|
|
||||||
type
|
|
||||||
}
|
|
||||||
conditions {
|
|
||||||
value
|
|
||||||
operator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment ExplorerOracleDataConnection on OracleSpec {
|
fragment ExplorerOracleDataConnection on OracleSpec {
|
||||||
dataConnection {
|
dataConnection {
|
||||||
pageInfo {
|
|
||||||
hasNextPage
|
|
||||||
}
|
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
externalData {
|
externalData {
|
||||||
@@ -81,6 +27,90 @@ fragment ExplorerOracleDataConnection on OracleSpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fragment ExplorerOracleDataSource on OracleSpec {
|
||||||
|
...ExplorerOracleDataConnection
|
||||||
|
dataSourceSpec {
|
||||||
|
spec {
|
||||||
|
id
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
status
|
||||||
|
data {
|
||||||
|
sourceType {
|
||||||
|
... on DataSourceDefinitionInternal {
|
||||||
|
sourceType {
|
||||||
|
... on DataSourceSpecConfigurationTime {
|
||||||
|
conditions {
|
||||||
|
value
|
||||||
|
operator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on DataSourceDefinitionExternal {
|
||||||
|
sourceType {
|
||||||
|
... on EthCallSpec {
|
||||||
|
abi
|
||||||
|
args
|
||||||
|
method
|
||||||
|
requiredConfirmations
|
||||||
|
address
|
||||||
|
normalisers {
|
||||||
|
name
|
||||||
|
expression
|
||||||
|
}
|
||||||
|
trigger {
|
||||||
|
trigger {
|
||||||
|
... on EthTimeTrigger {
|
||||||
|
initial
|
||||||
|
every
|
||||||
|
until
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filters {
|
||||||
|
key {
|
||||||
|
name
|
||||||
|
type
|
||||||
|
numberDecimalPlaces
|
||||||
|
}
|
||||||
|
conditions {
|
||||||
|
value
|
||||||
|
operator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on DataSourceSpecConfiguration {
|
||||||
|
signers {
|
||||||
|
signer {
|
||||||
|
... on ETHAddress {
|
||||||
|
address
|
||||||
|
}
|
||||||
|
... on PubKey {
|
||||||
|
key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filters {
|
||||||
|
key {
|
||||||
|
name
|
||||||
|
type
|
||||||
|
numberDecimalPlaces
|
||||||
|
}
|
||||||
|
conditions {
|
||||||
|
value
|
||||||
|
operator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
query ExplorerOracleSpecs {
|
query ExplorerOracleSpecs {
|
||||||
oracleSpecsConnection(pagination: { first: 50 }) {
|
oracleSpecsConnection(pagination: { first: 50 }) {
|
||||||
pageInfo {
|
pageInfo {
|
||||||
@@ -97,6 +127,5 @@ query ExplorerOracleSpecs {
|
|||||||
query ExplorerOracleSpecById($id: ID!) {
|
query ExplorerOracleSpecById($id: ID!) {
|
||||||
oracleSpec(oracleSpecId: $id) {
|
oracleSpec(oracleSpecId: $id) {
|
||||||
...ExplorerOracleDataSource
|
...ExplorerOracleDataSource
|
||||||
...ExplorerOracleDataConnection
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ fragment ExplorerOracleForMarketsMarket on Market {
|
|||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
... on Perpetual {
|
||||||
|
dataSourceSpecForSettlementData {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
dataSourceSpecForSettlementSchedule {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+90
-62
@@ -3,80 +3,25 @@ import * as Types from '@vegaprotocol/types';
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import * as Apollo from '@apollo/client';
|
import * as Apollo from '@apollo/client';
|
||||||
const defaultOptions = {} as const;
|
const defaultOptions = {} as const;
|
||||||
export type ExplorerOracleDataSourceFragment = { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } } } } } };
|
export type ExplorerOracleDataConnectionFragment = { __typename?: 'OracleSpec', dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } };
|
||||||
|
|
||||||
export type ExplorerOracleDataConnectionFragment = { __typename?: 'OracleSpec', dataConnection: { __typename?: 'OracleDataConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean }, edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } };
|
export type ExplorerOracleDataSourceFragment = { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec', abi?: Array<string> | null, args?: Array<string> | null, method: string, requiredConfirmations: number, address: string, normalisers?: Array<{ __typename?: 'Normaliser', name: string, expression: string }> | null, trigger: { __typename?: 'EthCallTrigger', trigger: { __typename?: 'EthTimeTrigger', initial?: any | null, every?: number | null, until?: any | null } }, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } };
|
||||||
|
|
||||||
export type ExplorerOracleSpecsQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
export type ExplorerOracleSpecsQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerOracleSpecsQuery = { __typename?: 'Query', oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean }, edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } } } } } } } | null> | null } | null };
|
export type ExplorerOracleSpecsQuery = { __typename?: 'Query', oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean }, edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec', abi?: Array<string> | null, args?: Array<string> | null, method: string, requiredConfirmations: number, address: string, normalisers?: Array<{ __typename?: 'Normaliser', name: string, expression: string }> | null, trigger: { __typename?: 'EthCallTrigger', trigger: { __typename?: 'EthTimeTrigger', initial?: any | null, every?: number | null, until?: any | null } }, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
|
||||||
|
|
||||||
export type ExplorerOracleSpecByIdQueryVariables = Types.Exact<{
|
export type ExplorerOracleSpecByIdQueryVariables = Types.Exact<{
|
||||||
id: Types.Scalars['ID'];
|
id: Types.Scalars['ID'];
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerOracleSpecByIdQuery = { __typename?: 'Query', oracleSpec?: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean }, edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } | null };
|
export type ExplorerOracleSpecByIdQuery = { __typename?: 'Query', oracleSpec?: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec', abi?: Array<string> | null, args?: Array<string> | null, method: string, requiredConfirmations: number, address: string, normalisers?: Array<{ __typename?: 'Normaliser', name: string, expression: string }> | null, trigger: { __typename?: 'EthCallTrigger', trigger: { __typename?: 'EthTimeTrigger', initial?: any | null, every?: number | null, until?: any | null } }, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } | null };
|
||||||
|
|
||||||
export const ExplorerOracleDataSourceFragmentDoc = gql`
|
|
||||||
fragment ExplorerOracleDataSource on OracleSpec {
|
|
||||||
dataSourceSpec {
|
|
||||||
spec {
|
|
||||||
id
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
status
|
|
||||||
data {
|
|
||||||
sourceType {
|
|
||||||
... on DataSourceDefinitionInternal {
|
|
||||||
sourceType {
|
|
||||||
... on DataSourceSpecConfigurationTime {
|
|
||||||
conditions {
|
|
||||||
value
|
|
||||||
operator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
... on DataSourceDefinitionExternal {
|
|
||||||
sourceType {
|
|
||||||
... on DataSourceSpecConfiguration {
|
|
||||||
signers {
|
|
||||||
signer {
|
|
||||||
... on ETHAddress {
|
|
||||||
address
|
|
||||||
}
|
|
||||||
... on PubKey {
|
|
||||||
key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filters {
|
|
||||||
key {
|
|
||||||
name
|
|
||||||
type
|
|
||||||
}
|
|
||||||
conditions {
|
|
||||||
value
|
|
||||||
operator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
export const ExplorerOracleDataConnectionFragmentDoc = gql`
|
export const ExplorerOracleDataConnectionFragmentDoc = gql`
|
||||||
fragment ExplorerOracleDataConnection on OracleSpec {
|
fragment ExplorerOracleDataConnection on OracleSpec {
|
||||||
dataConnection {
|
dataConnection {
|
||||||
pageInfo {
|
|
||||||
hasNextPage
|
|
||||||
}
|
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
externalData {
|
externalData {
|
||||||
@@ -104,6 +49,91 @@ export const ExplorerOracleDataConnectionFragmentDoc = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
export const ExplorerOracleDataSourceFragmentDoc = gql`
|
||||||
|
fragment ExplorerOracleDataSource on OracleSpec {
|
||||||
|
...ExplorerOracleDataConnection
|
||||||
|
dataSourceSpec {
|
||||||
|
spec {
|
||||||
|
id
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
status
|
||||||
|
data {
|
||||||
|
sourceType {
|
||||||
|
... on DataSourceDefinitionInternal {
|
||||||
|
sourceType {
|
||||||
|
... on DataSourceSpecConfigurationTime {
|
||||||
|
conditions {
|
||||||
|
value
|
||||||
|
operator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on DataSourceDefinitionExternal {
|
||||||
|
sourceType {
|
||||||
|
... on EthCallSpec {
|
||||||
|
abi
|
||||||
|
args
|
||||||
|
method
|
||||||
|
requiredConfirmations
|
||||||
|
address
|
||||||
|
normalisers {
|
||||||
|
name
|
||||||
|
expression
|
||||||
|
}
|
||||||
|
trigger {
|
||||||
|
trigger {
|
||||||
|
... on EthTimeTrigger {
|
||||||
|
initial
|
||||||
|
every
|
||||||
|
until
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filters {
|
||||||
|
key {
|
||||||
|
name
|
||||||
|
type
|
||||||
|
numberDecimalPlaces
|
||||||
|
}
|
||||||
|
conditions {
|
||||||
|
value
|
||||||
|
operator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on DataSourceSpecConfiguration {
|
||||||
|
signers {
|
||||||
|
signer {
|
||||||
|
... on ETHAddress {
|
||||||
|
address
|
||||||
|
}
|
||||||
|
... on PubKey {
|
||||||
|
key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filters {
|
||||||
|
key {
|
||||||
|
name
|
||||||
|
type
|
||||||
|
numberDecimalPlaces
|
||||||
|
}
|
||||||
|
conditions {
|
||||||
|
value
|
||||||
|
operator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
${ExplorerOracleDataConnectionFragmentDoc}`;
|
||||||
export const ExplorerOracleSpecsDocument = gql`
|
export const ExplorerOracleSpecsDocument = gql`
|
||||||
query ExplorerOracleSpecs {
|
query ExplorerOracleSpecs {
|
||||||
oracleSpecsConnection(pagination: {first: 50}) {
|
oracleSpecsConnection(pagination: {first: 50}) {
|
||||||
@@ -149,11 +179,9 @@ export const ExplorerOracleSpecByIdDocument = gql`
|
|||||||
query ExplorerOracleSpecById($id: ID!) {
|
query ExplorerOracleSpecById($id: ID!) {
|
||||||
oracleSpec(oracleSpecId: $id) {
|
oracleSpec(oracleSpecId: $id) {
|
||||||
...ExplorerOracleDataSource
|
...ExplorerOracleDataSource
|
||||||
...ExplorerOracleDataConnection
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
${ExplorerOracleDataSourceFragmentDoc}
|
${ExplorerOracleDataSourceFragmentDoc}`;
|
||||||
${ExplorerOracleDataConnectionFragmentDoc}`;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __useExplorerOracleSpecByIdQuery__
|
* __useExplorerOracleSpecByIdQuery__
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import * as Types from '@vegaprotocol/types';
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import * as Apollo from '@apollo/client';
|
import * as Apollo from '@apollo/client';
|
||||||
const defaultOptions = {} as const;
|
const defaultOptions = {} as const;
|
||||||
export type ExplorerOracleForMarketsMarketFragment = { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string } } } } };
|
export type ExplorerOracleForMarketsMarketFragment = { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string } } | { __typename?: 'Spot' } } } };
|
||||||
|
|
||||||
export type ExplorerOracleFormMarketsQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
export type ExplorerOracleFormMarketsQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerOracleFormMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string } } } } } }> } | null };
|
export type ExplorerOracleFormMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string } } | { __typename?: 'Spot' } } } } }> } | null };
|
||||||
|
|
||||||
export const ExplorerOracleForMarketsMarketFragmentDoc = gql`
|
export const ExplorerOracleForMarketsMarketFragmentDoc = gql`
|
||||||
fragment ExplorerOracleForMarketsMarket on Market {
|
fragment ExplorerOracleForMarketsMarket on Market {
|
||||||
@@ -24,6 +24,14 @@ export const ExplorerOracleForMarketsMarketFragmentDoc = gql`
|
|||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
... on Perpetual {
|
||||||
|
dataSourceSpecForSettlementData {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
dataSourceSpecForSettlementSchedule {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import { OracleData } from './oracle-data';
|
import { OracleData } from './oracle-data';
|
||||||
import type { ExplorerOracleDataConnectionFragment } from '../__generated__/Oracles';
|
import { type ExplorerOracleDataConnectionFragment } from '../__generated__/Oracles';
|
||||||
|
|
||||||
function renderComponent(data: ExplorerOracleDataConnectionFragment) {
|
type DataConnection = ExplorerOracleDataConnectionFragment['dataConnection'];
|
||||||
|
|
||||||
|
function renderComponent(
|
||||||
|
data: ExplorerOracleDataConnectionFragment['dataConnection']
|
||||||
|
) {
|
||||||
return <OracleData data={data} />;
|
return <OracleData data={data} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Oracle Data view', () => {
|
describe('Oracle Data view', () => {
|
||||||
it('Renders nothing when data is null', () => {
|
it('Renders nothing when data is null', () => {
|
||||||
const res = render(
|
const res = render(renderComponent(null as unknown as DataConnection));
|
||||||
renderComponent(null as unknown as ExplorerOracleDataConnectionFragment)
|
|
||||||
);
|
|
||||||
expect(res.container).toBeEmptyDOMElement();
|
expect(res.container).toBeEmptyDOMElement();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Renders nothing when dataConnection is empty', () => {
|
it('Renders nothing when dataConnection is empty', () => {
|
||||||
const res = render(
|
const res = render(renderComponent({} as DataConnection));
|
||||||
renderComponent({} as ExplorerOracleDataConnectionFragment)
|
|
||||||
);
|
|
||||||
expect(res.container).toBeEmptyDOMElement();
|
expect(res.container).toBeEmptyDOMElement();
|
||||||
});
|
});
|
||||||
it('Renders nothing when dataConnection has no edges', () => {
|
it('Renders nothing when dataConnection has no edges', () => {
|
||||||
@@ -26,7 +26,7 @@ describe('Oracle Data view', () => {
|
|||||||
dataConnection: {
|
dataConnection: {
|
||||||
edges: null,
|
edges: null,
|
||||||
},
|
},
|
||||||
} as ExplorerOracleDataConnectionFragment)
|
} as DataConnection)
|
||||||
);
|
);
|
||||||
expect(res.container).toBeEmptyDOMElement();
|
expect(res.container).toBeEmptyDOMElement();
|
||||||
});
|
});
|
||||||
@@ -37,7 +37,7 @@ describe('Oracle Data view', () => {
|
|||||||
dataConnection: {
|
dataConnection: {
|
||||||
edges: [],
|
edges: [],
|
||||||
},
|
},
|
||||||
} as unknown as ExplorerOracleDataConnectionFragment)
|
} as unknown as DataConnection)
|
||||||
);
|
);
|
||||||
expect(res.container).toBeEmptyDOMElement();
|
expect(res.container).toBeEmptyDOMElement();
|
||||||
});
|
});
|
||||||
@@ -47,20 +47,18 @@ describe('Oracle Data view', () => {
|
|||||||
it('Renders details component when there is data', () => {
|
it('Renders details component when there is data', () => {
|
||||||
const res = render(
|
const res = render(
|
||||||
renderComponent({
|
renderComponent({
|
||||||
dataConnection: {
|
edges: [
|
||||||
edges: [
|
{
|
||||||
{
|
node: {
|
||||||
node: {
|
externalData: {
|
||||||
externalData: {
|
data: {
|
||||||
data: {
|
broadcastAt: '2022-01-01',
|
||||||
broadcastAt: '2022-01-01',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
},
|
],
|
||||||
} as ExplorerOracleDataConnectionFragment)
|
} as DataConnection)
|
||||||
);
|
);
|
||||||
expect(res.getByText('Broadcast data')).toBeInTheDocument();
|
expect(res.getByText('Broadcast data')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import filter from 'recursive-key-filter';
|
|||||||
import type { ExplorerOracleDataConnectionFragment } from '../__generated__/Oracles';
|
import type { ExplorerOracleDataConnectionFragment } from '../__generated__/Oracles';
|
||||||
|
|
||||||
interface OracleDataTypeProps {
|
interface OracleDataTypeProps {
|
||||||
data: ExplorerOracleDataConnectionFragment;
|
data: ExplorerOracleDataConnectionFragment['dataConnection'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,12 +14,7 @@ interface OracleDataTypeProps {
|
|||||||
* that Does The Job, rather than because it's good.
|
* that Does The Job, rather than because it's good.
|
||||||
*/
|
*/
|
||||||
export function OracleData({ data }: OracleDataTypeProps) {
|
export function OracleData({ data }: OracleDataTypeProps) {
|
||||||
if (
|
if (!data || !data.edges?.length || data.edges.length > 1) {
|
||||||
!data ||
|
|
||||||
!data.dataConnection ||
|
|
||||||
!data.dataConnection.edges?.length ||
|
|
||||||
data.dataConnection.edges.length > 1
|
|
||||||
) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +22,7 @@ export function OracleData({ data }: OracleDataTypeProps) {
|
|||||||
<details data-testid="oracle-data">
|
<details data-testid="oracle-data">
|
||||||
<summary>{t('Broadcast data')}</summary>
|
<summary>{t('Broadcast data')}</summary>
|
||||||
<ul>
|
<ul>
|
||||||
{data.dataConnection.edges.map((d) => {
|
{data.edges.map((d) => {
|
||||||
if (!d) {
|
if (!d) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ interface OracleMarketsProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slightly misleadlingly names, OracleMarkets lists the market (almost always singular)
|
* Slightly misleading names, OracleMarkets lists the market (almost always singular)
|
||||||
* to which an oracle is attached. It also checks what it triggers, by checking on the
|
* to which an oracle is attached. It also checks what it triggers, by checking on the
|
||||||
* market whether it is attached to the dataSourceSpecForSettlementData or ..TradingTermination
|
* market whether it is attached to the dataSourceSpecForSettlementData or ..TradingTermination
|
||||||
*/
|
*/
|
||||||
@@ -27,8 +27,10 @@ export function OracleMarkets({ id }: OracleMarketsProps) {
|
|||||||
const m = markets.find((m) => {
|
const m = markets.find((m) => {
|
||||||
const p = m.tradableInstrument.instrument.product;
|
const p = m.tradableInstrument.instrument.product;
|
||||||
if (
|
if (
|
||||||
p.dataSourceSpecForSettlementData.id === id ||
|
((p.__typename === 'Future' || p.__typename === 'Perpetual') &&
|
||||||
p.dataSourceSpecForTradingTermination.id === id
|
p.dataSourceSpecForSettlementData.id === id) ||
|
||||||
|
('dataSourceSpecForTradingTermination' in p &&
|
||||||
|
p.dataSourceSpecForTradingTermination.id === id)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -36,15 +38,9 @@ export function OracleMarkets({ id }: OracleMarketsProps) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (m && m.id) {
|
if (m && m.id) {
|
||||||
const type =
|
|
||||||
id ===
|
|
||||||
m.tradableInstrument.instrument.product.dataSourceSpecForSettlementData
|
|
||||||
.id
|
|
||||||
? 'Settlement for'
|
|
||||||
: 'Termination for';
|
|
||||||
return (
|
return (
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableHeader scope="row">{type}</TableHeader>
|
<TableHeader scope="row">{getLabel(id, m)}</TableHeader>
|
||||||
<TableCell modifier="bordered" data-testid={`m-${m.id}`}>
|
<TableCell modifier="bordered" data-testid={`m-${m.id}`}>
|
||||||
<MarketLink id={m.id} />
|
<MarketLink id={m.id} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@@ -61,3 +57,38 @@ export function OracleMarkets({ id }: OracleMarketsProps) {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getLabel(
|
||||||
|
id: string,
|
||||||
|
m: ExplorerOracleForMarketsMarketFragment | null
|
||||||
|
): string {
|
||||||
|
const settlementId =
|
||||||
|
((m?.tradableInstrument?.instrument?.product?.__typename === 'Future' ||
|
||||||
|
m?.tradableInstrument?.instrument?.product?.__typename === 'Perpetual') &&
|
||||||
|
m?.tradableInstrument?.instrument?.product
|
||||||
|
?.dataSourceSpecForSettlementData?.id) ||
|
||||||
|
null;
|
||||||
|
|
||||||
|
const terminationId =
|
||||||
|
(m?.tradableInstrument?.instrument?.product?.__typename === 'Future' &&
|
||||||
|
m?.tradableInstrument?.instrument?.product
|
||||||
|
?.dataSourceSpecForTradingTermination?.id) ||
|
||||||
|
null;
|
||||||
|
|
||||||
|
const settlementScheduleId =
|
||||||
|
(m?.tradableInstrument?.instrument?.product?.__typename === 'Perpetual' &&
|
||||||
|
m?.tradableInstrument?.instrument?.product
|
||||||
|
?.dataSourceSpecForSettlementSchedule?.id) ||
|
||||||
|
null;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case settlementId:
|
||||||
|
return 'Settlement for';
|
||||||
|
case terminationId:
|
||||||
|
return 'Termination for';
|
||||||
|
case settlementScheduleId:
|
||||||
|
return 'Settlement schedule for';
|
||||||
|
default:
|
||||||
|
return 'Unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ export function OracleSigners({ sourceType }: OracleDetailsSignersProps) {
|
|||||||
if (sourceType.__typename !== 'DataSourceDefinitionExternal') {
|
if (sourceType.__typename !== 'DataSourceDefinitionExternal') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (!('signers' in sourceType.sourceType)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const signers = sourceType.sourceType.signers;
|
const signers = sourceType.sourceType.signers;
|
||||||
|
|
||||||
if (!signers || signers.length === 0) {
|
if (!signers || signers.length === 0) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export type SourceType =
|
|||||||
interface OracleDetailsProps {
|
interface OracleDetailsProps {
|
||||||
id: string;
|
id: string;
|
||||||
dataSource: ExplorerOracleDataSourceFragment;
|
dataSource: ExplorerOracleDataSourceFragment;
|
||||||
dataConnection?: ExplorerOracleDataConnectionFragment;
|
dataConnection: ExplorerOracleDataConnectionFragment['dataConnection'];
|
||||||
// Defaults to false. Hides the count of 'broadcasts' this oracle has seen
|
// Defaults to false. Hides the count of 'broadcasts' this oracle has seen
|
||||||
showBroadcasts?: boolean;
|
showBroadcasts?: boolean;
|
||||||
}
|
}
|
||||||
@@ -41,8 +41,7 @@ export const OracleDetails = ({
|
|||||||
showBroadcasts = false,
|
showBroadcasts = false,
|
||||||
}: OracleDetailsProps) => {
|
}: OracleDetailsProps) => {
|
||||||
const sourceType = dataSource.dataSourceSpec.spec.data.sourceType;
|
const sourceType = dataSource.dataSourceSpec.spec.data.sourceType;
|
||||||
const reportsCount: number =
|
const reportsCount: number = dataConnection.edges?.length || 0;
|
||||||
dataConnection?.dataConnection.edges?.length || 0;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user