Compare commits
173
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0aa0065b6 | ||
|
|
bb6ecd2c72 | ||
|
|
de62f09fda | ||
|
|
6d70b28f30 | ||
|
|
0d850bd8b9 | ||
|
|
44189591fc | ||
|
|
3ed2ec88d7 | ||
|
|
a21feea699 | ||
|
|
41fd14dd00 | ||
|
|
c5a27dc6a2 | ||
|
|
0a3b1cadba | ||
|
|
b953de953a | ||
|
|
5ddcb613e2 | ||
|
|
76c07992d3 | ||
|
|
46e2965fa2 | ||
|
|
532ad3a4b9 | ||
|
|
3a8b40d7a5 | ||
|
|
be38813a33 | ||
|
|
bf70dc33ec | ||
|
|
d6084e75a0 | ||
|
|
75e7cea32a | ||
|
|
b4e98e285e | ||
|
|
f62e29c67f | ||
|
|
94e7ad489f | ||
|
|
657942d995 | ||
|
|
a529b9b031 | ||
|
|
0f311611ba | ||
|
|
02bd031bee | ||
|
|
bd97651dd3 | ||
|
|
516b3e5b93 | ||
|
|
42a98b6a35 | ||
|
|
2002731c52 | ||
|
|
a49139f127 | ||
|
|
e216b23472 | ||
|
|
e52ae97233 | ||
|
|
1780f6fa7f | ||
|
|
8b91592b93 | ||
|
|
508274268d | ||
|
|
2a40d9ec4d | ||
|
|
efb746f373 | ||
|
|
6d2f367987 | ||
|
|
6b7bbc9c94 | ||
|
|
9153677a33 | ||
|
|
cff1818940 | ||
|
|
d05dd6e4cb | ||
|
|
4ef789e00a | ||
|
|
0bd13a5f7b | ||
|
|
67d38ff03e | ||
|
|
6aea10c27b | ||
|
|
27a9d5f247 | ||
|
|
261f32aa5b | ||
|
|
053775bef6 | ||
|
|
0660eda334 | ||
|
|
f22a3bc2d2 | ||
|
|
fde77ebccb | ||
|
|
e309669736 | ||
|
|
b1621d1191 | ||
|
|
39907f07db | ||
|
|
3dab5f3d9b | ||
|
|
3cf9ae7582 | ||
|
|
557894e2ef | ||
|
|
baf9875c69 | ||
|
|
51199b02ce | ||
|
|
bb826c88f0 | ||
|
|
0da20b750f | ||
|
|
e16c447564 | ||
|
|
a2170d27d6 | ||
|
|
00d840b7b3 | ||
|
|
2a4a05630f | ||
|
|
97f1f40f2c | ||
|
|
a8e6963521 | ||
|
|
a2bffa1dfd | ||
|
|
9253e8067a | ||
|
|
58972f0a11 | ||
|
|
a3c55fd7c3 | ||
|
|
c63cba1071 | ||
|
|
bc9d87fe30 | ||
|
|
6a21862378 | ||
|
|
0fb4348e9c | ||
|
|
b751bcf17d | ||
|
|
d32f27fcb1 | ||
|
|
d05cd6a2ed | ||
|
|
c003e5fa30 | ||
|
|
f62d3289ab | ||
|
|
a3d3d18c5c | ||
|
|
77ca101781 | ||
|
|
d238c37d0c | ||
|
|
79feb485f6 | ||
|
|
6aa5c3b6e3 | ||
|
|
82abc13fda | ||
|
|
933f07cddf | ||
|
|
c8067669c2 | ||
|
|
78f5a9c520 | ||
|
|
462066959d | ||
|
|
f12f5ab961 | ||
|
|
98b2460d8b | ||
|
|
67c182f3de | ||
|
|
68e0009ab0 | ||
|
|
ad74b12908 | ||
|
|
7fff33e493 | ||
|
|
e7cb2c8276 | ||
|
|
4adaeea40a | ||
|
|
d47d894147 | ||
|
|
515932d401 | ||
|
|
723ff2805d | ||
|
|
424cced4be | ||
|
|
b2c7ee82c5 | ||
|
|
4cc63be4f9 | ||
|
|
9fbb7a13e6 | ||
|
|
1874095222 | ||
|
|
e459e92127 | ||
|
|
4dd65b4923 | ||
|
|
5d792d2458 | ||
|
|
59b2f75b13 | ||
|
|
95775679ca | ||
|
|
4cffee29f8 | ||
|
|
bd70b0c233 | ||
|
|
145792f216 | ||
|
|
10add7c236 | ||
|
|
362a2031c7 | ||
|
|
5aaeb87059 | ||
|
|
d240dddab5 | ||
|
|
0af1d0ba82 | ||
|
|
665ab6693a | ||
|
|
902ee2696c | ||
|
|
3beeb0140c | ||
|
|
4b208e90bf | ||
|
|
ec837854cf | ||
|
|
8b94a75ba4 | ||
|
|
08c57b6759 | ||
|
|
bb2184498f | ||
|
|
8b07ce3024 | ||
|
|
8a110584dd | ||
|
|
b82615a3d8 | ||
|
|
f178b85846 | ||
|
|
0796f2b31f | ||
|
|
67be224138 | ||
|
|
51c426ef4b | ||
|
|
fa28d31ef3 | ||
|
|
201a586b05 | ||
|
|
7d96d9bcd1 | ||
|
|
345be81142 | ||
|
|
2221e9faca | ||
|
|
7c0139e107 | ||
|
|
a157ff1e05 | ||
|
|
2e9fa0c52e | ||
|
|
c0790c1e93 | ||
|
|
13c1044f8e | ||
|
|
cf9f313e4c | ||
|
|
f56d34fe6e | ||
|
|
1379366caa | ||
|
|
8958c12fe3 | ||
|
|
fef13874db | ||
|
|
40f02ecf89 | ||
|
|
41cd6b1455 | ||
|
|
3cd393dac0 | ||
|
|
a52e60d6a2 | ||
|
|
bc13f1b359 | ||
|
|
eb81f4ae44 | ||
|
|
51ab02a2e2 | ||
|
|
ffada1b93d | ||
|
|
9dda3f712b | ||
|
|
df20dbeee0 | ||
|
|
cdfd8a2d00 | ||
|
|
1e5c523bc4 | ||
|
|
37cd69ba6e | ||
|
|
2c11045dd9 | ||
|
|
9aef41a119 | ||
|
|
80ab8821d0 | ||
|
|
8a3657a9b9 | ||
|
|
a59f7dfd29 | ||
|
|
61471228aa | ||
|
|
70d748fb15 |
@@ -77,6 +77,7 @@
|
|||||||
"fixStyle": "inline-type-imports"
|
"fixStyle": "inline-type-imports"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"@typescript-eslint/no-useless-constructor": 0,
|
||||||
"curly": ["error", "multi-line"]
|
"curly": ["error", "multi-line"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
* text eol=lf
|
* text eol=lf
|
||||||
*.png binary
|
*.png binary
|
||||||
*.ico binary
|
*.ico binary
|
||||||
|
*.woff2 binary
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
create-docker-image:
|
create-docker-image:
|
||||||
name: Create docker image for console-test
|
name: Create docker image for console-test
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
timeout-minutes: 20
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# check-out frontend-monorepo
|
# check-out frontend-monorepo
|
||||||
@@ -138,7 +138,7 @@ jobs:
|
|||||||
name: run-tests
|
name: run-tests
|
||||||
runs-on: 8-cores
|
runs-on: 8-cores
|
||||||
needs: [create-docker-image, console-test-branch]
|
needs: [create-docker-image, console-test-branch]
|
||||||
timeout-minutes: 20
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# load docker image
|
# load docker image
|
||||||
@@ -205,7 +205,7 @@ jobs:
|
|||||||
# run tests
|
# run tests
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
|
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v --numprocesses 4 --dist loadfile --durations=45
|
||||||
working-directory: apps/trading/e2e
|
working-directory: apps/trading/e2e
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# upload traces
|
# upload traces
|
||||||
@@ -227,3 +227,46 @@ jobs:
|
|||||||
name: worker-logs
|
name: worker-logs
|
||||||
path: ./logs/
|
path: ./logs/
|
||||||
retention-days: 15
|
retention-days: 15
|
||||||
|
#----------------------------------------------
|
||||||
|
# ----- upload market-sim logs -----
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Prepare and Zip market-sim-logs
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
parent_dir="/tmp/market-sim-logs"
|
||||||
|
echo "Creating parent directory at $parent_dir"
|
||||||
|
mkdir -p "$parent_dir"
|
||||||
|
|
||||||
|
echo "Waiting for vega-sim-* folders to be created..."
|
||||||
|
sleep 10 # Waits 10 seconds to ensure all folders are created
|
||||||
|
|
||||||
|
echo "Before searching for vega-sim-* folders in /tmp..."
|
||||||
|
folders=$(find /tmp -mindepth 1 -type d -name 'vega-sim-*' -print) || echo "Find command failed with exit code $?"
|
||||||
|
|
||||||
|
echo "After searching for vega-sim-* folders in /tmp..."
|
||||||
|
|
||||||
|
if [ -z "$folders" ]; then
|
||||||
|
echo "No vega-sim-* folders found."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Moving vega-sim-* folders to $parent_dir"
|
||||||
|
echo "$folders" | xargs -I {} mv {} "$parent_dir/"
|
||||||
|
|
||||||
|
echo "Checking if $parent_dir is not empty..."
|
||||||
|
if [ "$(ls -A $parent_dir)" ]; then
|
||||||
|
echo "Zipping the parent directory..."
|
||||||
|
zip -r market-sim-logs.zip "$parent_dir" && echo "Zip file created successfully."
|
||||||
|
else
|
||||||
|
echo "$parent_dir is empty. No zip file created."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
shell: /usr/bin/bash -e {0}
|
||||||
|
|
||||||
|
- name: Upload market-sim-logs
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: market-sim-logs
|
||||||
|
path: market-sim-logs.zip
|
||||||
|
retention-days: 15
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
# Auto-format all files
|
||||||
|
yarn nx format:write
|
||||||
|
|
||||||
# Lint all staged files
|
# Lint all staged files
|
||||||
yarn lint-staged
|
yarn lint-staged
|
||||||
|
|||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
# Lint all staged files
|
# Lint all staged files - this brings more value as pre-commit
|
||||||
yarn nx format:check
|
# yarn nx format:check
|
||||||
|
|
||||||
# Test all projects with changes
|
# Test all projects with changes
|
||||||
yarn nx affected -t test --exclude trading
|
# yarn nx affected -t test --exclude trading
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ The front-end monorepo provides a toolkit for building apps that interact with V
|
|||||||
|
|
||||||
This repository is managed using [Nx](https://nx.dev).
|
This repository is managed using [Nx](https://nx.dev).
|
||||||
|
|
||||||
# 🔎 Applications in this repo
|
## 🔎 Applications in this repo
|
||||||
|
|
||||||
### [Block explorer](./apps/explorer)
|
### [Block explorer](./apps/explorer)
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ Hosting for static content being shared across apps, for example fonts.
|
|||||||
|
|
||||||
The utility dApp for validators wishing to add or remove themselves as a signer of the multisig contract.
|
The utility dApp for validators wishing to add or remove themselves as a signer of the multisig contract.
|
||||||
|
|
||||||
# 🧱 Libraries in this repo
|
## 🧱 Libraries in this repo
|
||||||
|
|
||||||
### [UI toolkit](./libs/ui-toolkit)
|
### [UI toolkit](./libs/ui-toolkit)
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ A utility library for connecting to the Ethereum network and interacting with Ve
|
|||||||
|
|
||||||
Generic react helpers that can be used across multiple applications, along with other utilities.
|
Generic react helpers that can be used across multiple applications, along with other utilities.
|
||||||
|
|
||||||
# 💻 Develop
|
## 💻 Develop
|
||||||
|
|
||||||
### Set up
|
### Set up
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ In CI linting, formatting and also run. These checks can be seen in the [CI work
|
|||||||
|
|
||||||
Visit the [Nx Documentation](https://nx.dev/getting-started/intro) to learn more.
|
Visit the [Nx Documentation](https://nx.dev/getting-started/intro) to learn more.
|
||||||
|
|
||||||
# 🐋 Hosting a console
|
## 🐋 Hosting a console
|
||||||
|
|
||||||
To host a console there are two possible build scenarios for running the frontends: nx performed **outside** or **inside** docker build. For specific build instructions follow [build instructions](#build-instructions).
|
To host a console there are two possible build scenarios for running the frontends: nx performed **outside** or **inside** docker build. For specific build instructions follow [build instructions](#build-instructions).
|
||||||
|
|
||||||
@@ -226,6 +226,6 @@ Note: The script is only needed if capsule was built for first time or fresh. To
|
|||||||
vega wallet service run -n DV --load-tokens --tokens-passphrase-file passphrase --no-version-check --automatic-consent --home ~/.vegacapsule/testnet/wallet
|
vega wallet service run -n DV --load-tokens --tokens-passphrase-file passphrase --no-version-check --automatic-consent --home ~/.vegacapsule/testnet/wallet
|
||||||
```
|
```
|
||||||
|
|
||||||
# 📑 License
|
## 📑 License
|
||||||
|
|
||||||
[MIT](./LICENSE)
|
[MIT](./LICENSE)
|
||||||
|
|||||||
@@ -24,10 +24,6 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
|||||||
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
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('type').should('have.text', 'NewMarket');
|
||||||
cy.get_element_by_col_id('state').should('have.text', 'Enacted');
|
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"]')
|
cy.get('[col-id="cDate"]')
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.should('match', dateTimeRegex);
|
.should('match', dateTimeRegex);
|
||||||
@@ -44,7 +40,7 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
|||||||
cy.getByTestId('icon-cross').click();
|
cy.getByTestId('icon-cross').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('Proposal page displayed on mobile', function () {
|
it('Proposal page displayed on mobile', function () {
|
||||||
const proposalTitle = 'Add Lorem Ipsum market';
|
const proposalTitle = 'Add Lorem Ipsum market';
|
||||||
|
|
||||||
cy.common_switch_to_mobile_and_click_toggle();
|
cy.common_switch_to_mobile_and_click_toggle();
|
||||||
@@ -55,7 +51,7 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to view new asset proposal', function () {
|
it.skip('Able to view new asset proposal', function () {
|
||||||
const proposalTitle = 'Test new asset proposal';
|
const proposalTitle = 'Test new asset proposal';
|
||||||
const newAssetProposalBody = getNewAssetTxBody();
|
const newAssetProposalBody = getNewAssetTxBody();
|
||||||
cy.VegaWalletSubmitProposal(newAssetProposalBody);
|
cy.VegaWalletSubmitProposal(newAssetProposalBody);
|
||||||
@@ -73,10 +69,6 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
|||||||
'have.text',
|
'have.text',
|
||||||
'Waiting for Node Vote'
|
'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"]')
|
cy.get('[col-id="cDate"]')
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.should('match', dateTimeRegex);
|
.should('match', dateTimeRegex);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.rocks
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.rocks
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
|
||||||
NX_VEGA_ENV=STAGNET1
|
NX_VEGA_ENV=STAGNET1
|
||||||
@@ -9,7 +8,6 @@ NX_VEGA_WALLET_URL=http://localhost:1789
|
|||||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||||
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.rocks/rest
|
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.rocks/rest
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.stagnet1.vega.rocks
|
NX_VEGA_GOVERNANCE_URL=https://governance.stagnet1.vega.rocks
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_VEGA_ENV=CUSTOM
|
NX_VEGA_ENV=CUSTOM
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
NX_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
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
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
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://dev.governance.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://dev.governance.vega.xyz
|
||||||
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/maste
|
|||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
NX_VEGA_ENV=MAINNET
|
NX_VEGA_ENV=MAINNET
|
||||||
NX_BLOCK_EXPLORER=https://be.vega.community/rest
|
NX_BLOCK_EXPLORER=https://be.vega.community/rest
|
||||||
NX_ETHERSCAN_URL=https://etherscan.io
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-inter
|
|||||||
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
||||||
NX_VEGA_ENV=MAINNET_MIRROR
|
NX_VEGA_ENV=MAINNET_MIRROR
|
||||||
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.rocks/rest
|
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.rocks/rest
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
|
NX_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/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-inter
|
|||||||
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
|
||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
|
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
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/maste
|
|||||||
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
||||||
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
||||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_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_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ NX_TENDERMINT_URL=http://localhost:26607/
|
|||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket
|
||||||
NX_VEGA_ENV=CUSTOM
|
NX_VEGA_ENV=CUSTOM
|
||||||
NX_BLOCK_EXPLORER=
|
NX_BLOCK_EXPLORER=
|
||||||
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
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-web
|
|||||||
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
||||||
import { RouterProvider } from 'react-router-dom';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { router } from './routes/router-config';
|
import { useRouterConfig } from './routes/router-config';
|
||||||
|
import { createBrowserRouter } from 'react-router-dom';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
@@ -38,7 +39,10 @@ function App() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Suspense fallback={splashLoading}>
|
<Suspense fallback={splashLoading}>
|
||||||
<RouterProvider router={router} fallbackElement={splashLoading} />
|
<RouterProvider
|
||||||
|
router={createBrowserRouter(useRouterConfig())}
|
||||||
|
fallbackElement={splashLoading}
|
||||||
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</NodeGuard>
|
</NodeGuard>
|
||||||
<NodeSwitcherDialog
|
<NodeSwitcherDialog
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const ref = useRef<AgGridReact>(null);
|
const ref = useRef<AgGridReact>(null);
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
ref.current?.columnApi.setColumnsVisible(
|
ref.current?.api.setColumnsVisible(
|
||||||
['id', 'type', 'status'],
|
['id', 'type', 'status'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { Routes } from '../../routes/route-names';
|
|||||||
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
||||||
import type { Navigable } from '../../routes/router-config';
|
import type { Navigable } from '../../routes/router-config';
|
||||||
import { isNavigable } from '../../routes/router-config';
|
import { isNavigable } from '../../routes/router-config';
|
||||||
import { routerConfig } from '../../routes/router-config';
|
import { useRouterConfig } from '../../routes/router-config';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import compact from 'lodash/compact';
|
import compact from 'lodash/compact';
|
||||||
import { Search } from '../search';
|
import { Search } from '../search';
|
||||||
@@ -26,6 +26,7 @@ const routeToNavigationItem = (r: Navigable) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
|
const routerConfig = useRouterConfig();
|
||||||
const isHome = Boolean(useMatch(Routes.HOME));
|
const isHome = Boolean(useMatch(Routes.HOME));
|
||||||
const pages = routerConfig[0].children || [];
|
const pages = routerConfig[0].children || [];
|
||||||
const mainItems = compact(
|
const mainItems = compact(
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { DATA_SOURCES } from '../../../config';
|
|
||||||
import Hash from '../hash';
|
|
||||||
|
|
||||||
export enum EthExplorerLinkTypes {
|
|
||||||
block = 'block',
|
|
||||||
address = 'address',
|
|
||||||
tx = 'tx',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type EthExplorerLinkProps = Partial<typeof HTMLAnchorElement> & {
|
|
||||||
id: string;
|
|
||||||
type: EthExplorerLinkTypes;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const EthExplorerLink = ({
|
|
||||||
id,
|
|
||||||
type,
|
|
||||||
...props
|
|
||||||
}: EthExplorerLinkProps) => {
|
|
||||||
const link = `${DATA_SOURCES.ethExplorerUrl}/${type}/${id}`;
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
className="underline external font-mono"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
{...props}
|
|
||||||
href={link}
|
|
||||||
>
|
|
||||||
<Hash text={id} />
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import type { ChainIdMapping } from './external-chain';
|
||||||
|
import { SUPPORTED_CHAIN_IDS, SUPPORTED_CHAIN_LABELS } from './external-chain';
|
||||||
|
|
||||||
|
export const SUPPORTED_CHAIN_ICON_URLS: ChainIdMapping = {
|
||||||
|
'1': '/assets/chain-eth-logo.svg',
|
||||||
|
'100': '/assets/chain-gno-logo.svg',
|
||||||
|
'42161': '/assets/chain-arb-logo.svg',
|
||||||
|
'11155111': '/assets/chain-eth-logo.svg',
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ExternalChainIconProps = {
|
||||||
|
chainId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ExternalChainIcon = ({
|
||||||
|
// If chainID is not provided, default to a non-existent chain
|
||||||
|
chainId = '-1',
|
||||||
|
}: ExternalChainIconProps) => {
|
||||||
|
if (SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
||||||
|
const url = SUPPORTED_CHAIN_ICON_URLS[chainId];
|
||||||
|
const alt = SUPPORTED_CHAIN_LABELS[chainId];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
src={url}
|
||||||
|
className="inline-block w-4 h-4 mr-1 dark:invert"
|
||||||
|
alt={alt}
|
||||||
|
title={alt}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
export type ChainIdMapping = {
|
||||||
|
[K in typeof SUPPORTED_CHAIN_IDS[number]]: string;
|
||||||
|
};
|
||||||
|
export const SUPPORTED_CHAIN_IDS: string[] = ['1', '100', '42161', '11155111'];
|
||||||
|
|
||||||
|
export const SUPPORTED_CHAIN_LABELS: ChainIdMapping = {
|
||||||
|
'1': 'Ethereum',
|
||||||
|
'100': 'Gnosis',
|
||||||
|
'42161': 'Arbitrum',
|
||||||
|
'11155111': 'Sepolia',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getExternalExplorerLink(chainId: string, type: string) {
|
||||||
|
if (SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
||||||
|
switch (chainId) {
|
||||||
|
case '1':
|
||||||
|
return 'https://etherscan.io';
|
||||||
|
case '100':
|
||||||
|
return 'https://gnosisscan.io';
|
||||||
|
case '42161':
|
||||||
|
return 'https://arbiscan.io';
|
||||||
|
case '11155111':
|
||||||
|
return 'https://sepolia.etherscan.io';
|
||||||
|
default:
|
||||||
|
return '#';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return '#';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getExternalChainLabel(chainId?: string) {
|
||||||
|
if (chainId && SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
||||||
|
return SUPPORTED_CHAIN_LABELS[chainId];
|
||||||
|
} else {
|
||||||
|
return 'Custom Chain';
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
import Hash from '../hash';
|
||||||
|
import { getExternalExplorerLink } from './external-chain';
|
||||||
|
import { ExternalChainIcon } from './external-chain-icon';
|
||||||
|
|
||||||
|
export enum EthExplorerLinkTypes {
|
||||||
|
block = 'block',
|
||||||
|
address = 'address',
|
||||||
|
tx = 'tx',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ExternalExplorerLinkProps = Partial<typeof HTMLAnchorElement> & {
|
||||||
|
id: string;
|
||||||
|
type: EthExplorerLinkTypes;
|
||||||
|
// Defaults to Ethereum Mainnet, as chain support was added late
|
||||||
|
chain?: string;
|
||||||
|
code?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ExternalExplorerLink = ({
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
chain = '1',
|
||||||
|
code = false,
|
||||||
|
...props
|
||||||
|
}: ExternalExplorerLinkProps) => {
|
||||||
|
const link = `${getExternalExplorerLink(chain, type)}/${type}/${id}${
|
||||||
|
code ? '#code' : ''
|
||||||
|
}`;
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
className="underline external font-mono"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
{...props}
|
||||||
|
href={link}
|
||||||
|
>
|
||||||
|
<ExternalChainIcon chainId={chain} />
|
||||||
|
<Hash text={id} />
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export type HashProps = {
|
export type HashProps = React.HTMLProps<HTMLSpanElement> & {
|
||||||
text: string;
|
text: string;
|
||||||
truncate?: boolean;
|
truncate?: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ export { default as BlockLink } from './block-link/block-link';
|
|||||||
export { default as PartyLink } from './party-link/party-link';
|
export { default as PartyLink } from './party-link/party-link';
|
||||||
export { default as NodeLink } from './node-link/node-link';
|
export { default as NodeLink } from './node-link/node-link';
|
||||||
export { default as MarketLink } from './market-link/market-link';
|
export { default as MarketLink } from './market-link/market-link';
|
||||||
|
export { default as NetworkParameterLink } from './network-parameter-link/network-parameter-link';
|
||||||
export * from './asset-link/asset-link';
|
export * from './asset-link/asset-link';
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Routes } from '../../../routes/route-names';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import type { ComponentProps } from 'react';
|
||||||
|
import Hash from '../hash';
|
||||||
|
|
||||||
|
export type NetworkParameterLinkProps = Partial<ComponentProps<typeof Link>> & {
|
||||||
|
parameter: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Links a given network parameter to the relevant page and anchor on the page
|
||||||
|
*/
|
||||||
|
const NetworkParameterLink = ({
|
||||||
|
parameter,
|
||||||
|
...props
|
||||||
|
}: NetworkParameterLinkProps) => {
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
className="underline"
|
||||||
|
{...props}
|
||||||
|
to={`/${Routes.NETWORK_PARAMETERS}#${parameter}`}
|
||||||
|
>
|
||||||
|
<Hash text={parameter} />
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NetworkParameterLink;
|
||||||
@@ -60,7 +60,7 @@ const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="whitespace-nowrap">
|
<span>
|
||||||
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
||||||
<Link
|
<Link
|
||||||
className="underline font-mono"
|
className="underline font-mono"
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
query ExplorerProposal($id: ID!) {
|
query ExplorerProposal($id: ID!) {
|
||||||
proposal(id: $id) {
|
proposal(id: $id) {
|
||||||
id
|
... on Proposal {
|
||||||
rationale {
|
id
|
||||||
title
|
rationale {
|
||||||
description
|
title
|
||||||
|
description
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-5
@@ -8,16 +8,18 @@ export type ExplorerProposalQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerProposalQuery = { __typename?: 'Query', proposal?: { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null };
|
export type ExplorerProposalQuery = { __typename?: 'Query', proposal?: { __typename?: 'BatchProposal' } | { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null };
|
||||||
|
|
||||||
|
|
||||||
export const ExplorerProposalDocument = gql`
|
export const ExplorerProposalDocument = gql`
|
||||||
query ExplorerProposal($id: ID!) {
|
query ExplorerProposal($id: ID!) {
|
||||||
proposal(id: $id) {
|
proposal(id: $id) {
|
||||||
id
|
... on Proposal {
|
||||||
rationale {
|
id
|
||||||
title
|
rationale {
|
||||||
description
|
title
|
||||||
|
description
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ import { MockedProvider } from '@apollo/client/testing';
|
|||||||
import type { MockedResponse } from '@apollo/client/testing';
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import ProposalLink from './proposal-link';
|
import ProposalLink from './proposal-link';
|
||||||
import { ExplorerProposalDocument } from './__generated__/Proposal';
|
import {
|
||||||
|
ExplorerProposalDocument,
|
||||||
|
type ExplorerProposalQuery,
|
||||||
|
type ExplorerProposalQueryVariables,
|
||||||
|
} from './__generated__/Proposal';
|
||||||
import { GraphQLError } from 'graphql';
|
import { GraphQLError } from 'graphql';
|
||||||
|
|
||||||
function renderComponent(id: string, mocks: MockedResponse[]) {
|
function renderComponent(id: string, mocks: MockedResponse[]) {
|
||||||
@@ -23,7 +27,10 @@ describe('Proposal link component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Renders the ID on error', async () => {
|
it('Renders the ID on error', async () => {
|
||||||
const mock = {
|
const mock: MockedResponse<
|
||||||
|
ExplorerProposalQuery,
|
||||||
|
ExplorerProposalQueryVariables
|
||||||
|
> = {
|
||||||
request: {
|
request: {
|
||||||
query: ExplorerProposalDocument,
|
query: ExplorerProposalDocument,
|
||||||
variables: {
|
variables: {
|
||||||
@@ -40,17 +47,22 @@ describe('Proposal link component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Renders the proposal title when the query returns a result', async () => {
|
it('Renders the proposal title when the query returns a result', async () => {
|
||||||
const mock = {
|
const proposalId = '123';
|
||||||
|
const mock: MockedResponse<
|
||||||
|
ExplorerProposalQuery,
|
||||||
|
ExplorerProposalQueryVariables
|
||||||
|
> = {
|
||||||
request: {
|
request: {
|
||||||
query: ExplorerProposalDocument,
|
query: ExplorerProposalDocument,
|
||||||
variables: {
|
variables: {
|
||||||
id: '123',
|
id: proposalId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
data: {
|
data: {
|
||||||
proposal: {
|
proposal: {
|
||||||
id: '123',
|
__typename: 'Proposal',
|
||||||
|
id: proposalId,
|
||||||
rationale: {
|
rationale: {
|
||||||
title: 'test-title',
|
title: 'test-title',
|
||||||
description: 'test description',
|
description: 'test description',
|
||||||
@@ -60,13 +72,16 @@ describe('Proposal link component', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = render(renderComponent('123', [mock]));
|
const res = render(renderComponent(proposalId, [mock]));
|
||||||
expect(res.getByText('123')).toBeInTheDocument();
|
expect(res.getByText(proposalId)).toBeInTheDocument();
|
||||||
expect(await res.findByText('test-title')).toBeInTheDocument();
|
expect(await res.findByText('test-title')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Leaves the proposal id when the market is not found', async () => {
|
it('Leaves the proposal id when the market is not found', async () => {
|
||||||
const mock = {
|
const mock: MockedResponse<
|
||||||
|
ExplorerProposalQuery,
|
||||||
|
ExplorerProposalQueryVariables
|
||||||
|
> = {
|
||||||
request: {
|
request: {
|
||||||
query: ExplorerProposalDocument,
|
query: ExplorerProposalDocument,
|
||||||
variables: {
|
variables: {
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { useExplorerProposalQuery } from './__generated__/Proposal';
|
import {
|
||||||
|
useExplorerProposalQuery,
|
||||||
|
type ExplorerProposalQuery,
|
||||||
|
} from './__generated__/Proposal';
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { ENV } from '../../../config/env';
|
import { ENV } from '../../../config/env';
|
||||||
import Hash from '../hash';
|
import Hash from '../hash';
|
||||||
|
|
||||||
export type ProposalLinkProps = {
|
export type ProposalLinkProps = {
|
||||||
id: string;
|
id: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
@@ -16,8 +20,13 @@ const ProposalLink = ({ id, text }: ProposalLinkProps) => {
|
|||||||
variables: { id },
|
variables: { id },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const proposal = data?.proposal as Extract<
|
||||||
|
ExplorerProposalQuery['proposal'],
|
||||||
|
{ __typename?: 'Proposal' }
|
||||||
|
>;
|
||||||
|
|
||||||
const base = ENV.dataSources.governanceUrl;
|
const base = ENV.dataSources.governanceUrl;
|
||||||
const label = data?.proposal?.rationale.title || id;
|
const label = proposal?.rationale?.title || id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ExternalLink href={`${base}/proposals/${id}`}>
|
<ExternalLink href={`${base}/proposals/${id}`}>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||||
import {
|
import {
|
||||||
|
LiquidationStrategyInfoPanel,
|
||||||
LiquidityPriceRangeInfoPanel,
|
LiquidityPriceRangeInfoPanel,
|
||||||
LiquiditySLAParametersInfoPanel,
|
LiquiditySLAParametersInfoPanel,
|
||||||
MarginScalingFactorsPanel,
|
MarginScalingFactorsPanel,
|
||||||
@@ -94,6 +95,8 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
<h2 className={headerClassName}>{t('Liquidation strategy')}</h2>
|
||||||
|
<LiquidationStrategyInfoPanel market={market} />
|
||||||
<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 price range')}</h2>
|
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
const gridRef = useRef<AgGridReact>(null);
|
const gridRef = useRef<AgGridReact>(null);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
gridRef.current?.columnApi.setColumnsVisible(
|
gridRef.current?.api.setColumnsVisible(
|
||||||
['id', 'state', 'asset'],
|
['id', 'state', 'asset'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { render, waitFor } from '@testing-library/react';
|
import { render, waitFor } from '@testing-library/react';
|
||||||
import {
|
import { NestedDataList, sortNestedDataByChildren } from './nested-data-list';
|
||||||
BORDER_COLOURS,
|
|
||||||
NestedDataList,
|
|
||||||
sortNestedDataByChildren,
|
|
||||||
} from './nested-data-list';
|
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
const mockData = {
|
const mockData = {
|
||||||
@@ -61,38 +57,6 @@ describe('NestedDataList', () => {
|
|||||||
expect(parent[0].querySelector('li')).toHaveClass('pl-4 border-l-4 pt-2');
|
expect(parent[0].querySelector('li')).toHaveClass('pl-4 border-l-4 pt-2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should repeat the border colours in the correct order', () => {
|
|
||||||
const colourMockData = {
|
|
||||||
t0: {
|
|
||||||
t1: {
|
|
||||||
t2: {
|
|
||||||
t3: {
|
|
||||||
t4: {
|
|
||||||
t5: {
|
|
||||||
t6: {
|
|
||||||
t7: {
|
|
||||||
t8: {
|
|
||||||
hello: 'world',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const tree = render(<NestedDataList data={colourMockData} />);
|
|
||||||
const { getByTestId } = tree;
|
|
||||||
|
|
||||||
for (let i = 0; i < 8; i++) {
|
|
||||||
const item = getByTestId(`T${i}`);
|
|
||||||
const expected = BORDER_COLOURS.light[i % 5];
|
|
||||||
expect(item.style.borderColor.toUpperCase()).toBe(expected);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should sort the data by values with children', () => {
|
it('should sort the data by values with children', () => {
|
||||||
const mockData = {
|
const mockData = {
|
||||||
nonce: '5980890939790185837',
|
nonce: '5980890939790185837',
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Time } from '../time';
|
|||||||
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
|
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
|
||||||
import SizeInMarket from '../size-in-market/size-in-market';
|
import SizeInMarket from '../size-in-market/size-in-market';
|
||||||
import { TxOrderPeggedReference } from '../txs/details/order/tx-order-peg';
|
import { TxOrderPeggedReference } from '../txs/details/order/tx-order-peg';
|
||||||
|
import { OrderTypeMapping } from '@vegaprotocol/types';
|
||||||
|
|
||||||
export interface DeterministicOrderDetailsProps {
|
export interface DeterministicOrderDetailsProps {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -59,7 +60,7 @@ const DeterministicOrderDetails = ({
|
|||||||
const o = data.orderByID;
|
const o = data.orderByID;
|
||||||
return (
|
return (
|
||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<div className="mb-12 lg:mb-0">
|
<div className="mb-0">
|
||||||
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
||||||
<h2 className="text-3xl font-bold mb-4 display-5">
|
<h2 className="text-3xl font-bold mb-4 display-5">
|
||||||
<abbr title={tifFull[o.timeInForce]} className="bb-dotted mr-2">
|
<abbr title={tifFull[o.timeInForce]} className="bb-dotted mr-2">
|
||||||
@@ -69,7 +70,7 @@ const DeterministicOrderDetails = ({
|
|||||||
<span className="mx-5 text-base">@</span>
|
<span className="mx-5 text-base">@</span>
|
||||||
<PriceInMarket price={o.price} marketId={o.market.id} />
|
<PriceInMarket price={o.price} marketId={o.market.id} />
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-200">
|
<p className="text-gray-400 dark:text-gray-600">
|
||||||
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
|
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
|
||||||
</p>
|
</p>
|
||||||
{o.peggedOrder ? (
|
{o.peggedOrder ? (
|
||||||
@@ -83,15 +84,14 @@ const DeterministicOrderDetails = ({
|
|||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{o.reference ? (
|
{o.reference ? (
|
||||||
<p className="text-gray-500 mt-4">
|
<p className="text-gray-500 mt-4">
|
||||||
<span>{t('Reference')}</span>: {o.reference}
|
<span>{t('Reference')}</span>: {o.reference}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="grid md:grid-cols-4 gap-x-6 mt-4">
|
<div className="grid grid-cols-2 md:grid-cols-5 gap-x-6 mt-4">
|
||||||
<div className="mb-12 md:mb-0">
|
<div className="mb-6 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
||||||
{t('Status')}
|
{t('Status')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
||||||
@@ -99,21 +99,33 @@ const DeterministicOrderDetails = ({
|
|||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-12 md:mb-0">
|
<div className="mb-6 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">{t('Size')}</h2>
|
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
||||||
|
{t('Size')}
|
||||||
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
<SizeInMarket size={o.size} marketId={o.market.id} />
|
<SizeInMarket size={o.size} marketId={o.market.id} />
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="">
|
<div className="mb-6 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
||||||
{t('Version')}
|
{t('Version')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
{o.version}
|
{o.version}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
{o.type ? (
|
||||||
|
<div className="mb-6 md:mb-0">
|
||||||
|
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
||||||
|
{t('Type')}
|
||||||
|
</h2>
|
||||||
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
|
{OrderTypeMapping[o.type]}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { type ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
import { type ProposalListFieldsFragment } 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 { AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||||
@@ -12,12 +11,7 @@ import { type ColDef } from 'ag-grid-community';
|
|||||||
import type { RowClickedEvent } from 'ag-grid-community';
|
import type { RowClickedEvent } from 'ag-grid-community';
|
||||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import {
|
|
||||||
NetworkParams,
|
|
||||||
useNetworkParams,
|
|
||||||
} from '@vegaprotocol/network-parameters';
|
|
||||||
import { ProposalStateMapping } from '@vegaprotocol/types';
|
import { ProposalStateMapping } from '@vegaprotocol/types';
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
||||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||||
import { JsonViewerDialog } from '../dialogs/json-viewer-dialog';
|
import { JsonViewerDialog } from '../dialogs/json-viewer-dialog';
|
||||||
@@ -31,24 +25,16 @@ type ProposalsTableProps = {
|
|||||||
data: ProposalListFieldsFragment[] | null;
|
data: ProposalListFieldsFragment[] | null;
|
||||||
};
|
};
|
||||||
export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
||||||
const { params } = useNetworkParams([
|
|
||||||
NetworkParams.governance_proposal_market_requiredMajority,
|
|
||||||
]);
|
|
||||||
const tokenLink = useLinks(DApp.Governance);
|
const tokenLink = useLinks(DApp.Governance);
|
||||||
const requiredMajorityPercentage = useMemo(() => {
|
|
||||||
const requiredMajority =
|
|
||||||
params?.governance_proposal_market_requiredMajority ?? 1;
|
|
||||||
return new BigNumber(requiredMajority).times(100);
|
|
||||||
}, [params?.governance_proposal_market_requiredMajority]);
|
|
||||||
|
|
||||||
const gridRef = useRef<AgGridReact>(null);
|
const gridRef = useRef<AgGridReact>(null);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
gridRef.current?.columnApi.setColumnsVisible(
|
gridRef.current?.api.setColumnsVisible(
|
||||||
['voting', 'cDate', 'eDate', 'type'],
|
['voting', 'cDate', 'eDate', 'type'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
gridRef.current?.columnApi.setColumnWidth(
|
gridRef.current?.api.setColumnWidth(
|
||||||
'actions',
|
'actions',
|
||||||
window.innerWidth > BREAKPOINT_MD ? 221 : 80
|
window.innerWidth > BREAKPOINT_MD ? 221 : 80
|
||||||
);
|
);
|
||||||
@@ -90,33 +76,6 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
return value ? ProposalStateMapping[value] : '-';
|
return value ? ProposalStateMapping[value] : '-';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
colId: 'voting',
|
|
||||||
maxWidth: 100,
|
|
||||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
|
||||||
headerName: t('Voting'),
|
|
||||||
cellRenderer: ({
|
|
||||||
data,
|
|
||||||
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
|
|
||||||
if (data) {
|
|
||||||
const yesTokens = new BigNumber(data.votes.yes.totalTokens);
|
|
||||||
const noTokens = new BigNumber(data.votes.no.totalTokens);
|
|
||||||
const totalTokensVoted = yesTokens.plus(noTokens);
|
|
||||||
const yesPercentage = totalTokensVoted.isZero()
|
|
||||||
? new BigNumber(0)
|
|
||||||
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
|
||||||
return (
|
|
||||||
<div className="flex h-full items-center justify-center pt-2 uppercase">
|
|
||||||
<VoteProgress
|
|
||||||
threshold={requiredMajorityPercentage}
|
|
||||||
progress={yesPercentage}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return '-';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
colId: 'cDate',
|
colId: 'cDate',
|
||||||
maxWidth: 150,
|
maxWidth: 150,
|
||||||
@@ -184,7 +143,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[requiredMajorityPercentage, tokenLink]
|
[tokenLink]
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -30,12 +30,12 @@ export const Signature = ({ signature }: SignatureProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="inline-flex border rounded signature-component relative pr-[20px]">
|
<div className="inline-flex border rounded signature-component relative pr-[20px]">
|
||||||
<span
|
<div
|
||||||
className="bg-gray-100 px-2.5 py-0.5 text-xs text-gray-500 select-none cursor-default"
|
className="bg-gray-100 px-2.5 py-0.5 text-xs text-gray-500 select-none cursor-default"
|
||||||
title={`Version ${signature.version}`}
|
title={`${signature.algo}`}
|
||||||
>
|
>
|
||||||
{signature.algo}
|
<span>v{signature.version}</span>
|
||||||
</span>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
isOpen
|
isOpen
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { TableCell, TableRow } from '../../../table';
|
import { TableCell, TableRow } from '../../../table';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
import { getExternalChainLabel } from '../../../links/external-explorer-link/external-chain';
|
||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
|
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
|
||||||
import { BigNumber } from 'ethers';
|
import { BigNumber } from 'ethers';
|
||||||
@@ -44,10 +45,10 @@ export const TxDetailsContractCall = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!contractCall || !contractCall.result) {
|
if (!contractCall) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const chainLabel = getExternalChainLabel(contractCall.sourceChainId);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{contractCall.specId && (
|
{contractCall.specId && (
|
||||||
@@ -64,9 +65,12 @@ export const TxDetailsContractCall = ({
|
|||||||
)}
|
)}
|
||||||
{contractCall.blockHeight && (
|
{contractCall.blockHeight && (
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('ETH block')}</TableCell>
|
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
{chainLabel} {t('block')}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<ExternalExplorerLink
|
||||||
|
chain={contractCall.sourceChainId}
|
||||||
id={contractCall.blockHeight}
|
id={contractCall.blockHeight}
|
||||||
type={EthExplorerLinkTypes.block}
|
type={EthExplorerLinkTypes.block}
|
||||||
/>
|
/>
|
||||||
@@ -75,14 +79,24 @@ export const TxDetailsContractCall = ({
|
|||||||
)}
|
)}
|
||||||
{data?.oracleSpec?.dataSourceSpec && (
|
{data?.oracleSpec?.dataSourceSpec && (
|
||||||
<OracleEthSource
|
<OracleEthSource
|
||||||
|
chain={contractCall.sourceChainId}
|
||||||
sourceType={data.oracleSpec.dataSourceSpec.spec.data.sourceType}
|
sourceType={data.oracleSpec.dataSourceSpec.spec.data.sourceType}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<TableRow modifier="bordered">
|
{contractCall.error && (
|
||||||
<TableCell>{t('Result')}</TableCell>
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{decodeEthCallResult(contractCall.result)}</TableCell>
|
<TableCell>{t('Call error')}</TableCell>
|
||||||
</TableRow>
|
<TableCell>{contractCall.error}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{contractCall.result && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Result')}</TableCell>
|
||||||
|
<TableCell>{decodeEthCallResult(contractCall.result)}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+3
-3
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { AssetLink } from '../../../links';
|
import { AssetLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventErc20AssetLimitsUpdatedProps {
|
interface TxDetailsChainEventErc20AssetLimitsUpdatedProps {
|
||||||
assetLimitsUpdated: components['schemas']['vegaERC20AssetLimitsUpdated'];
|
assetLimitsUpdated: components['schemas']['vegaERC20AssetLimitsUpdated'];
|
||||||
@@ -42,7 +42,7 @@ export const TxDetailsChainEventErc20AssetLimitsUpdated = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('ERC20 asset')}</TableCell>
|
<TableCell>{t('ERC20 asset')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={assetLimitsUpdated.sourceEthereumAddress}
|
id={assetLimitsUpdated.sourceEthereumAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { AssetLink } from '../../../links';
|
import { AssetLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventErc20AssetListProps {
|
interface TxDetailsChainEventErc20AssetListProps {
|
||||||
assetList: components['schemas']['vegaERC20AssetList'];
|
assetList: components['schemas']['vegaERC20AssetList'];
|
||||||
@@ -32,7 +32,7 @@ export const TxDetailsChainEventErc20AssetList = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Source')}</TableCell>
|
<TableCell>{t('Source')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={assetList.assetSource}
|
id={assetList.assetSource}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { AssetLink, PartyLink } from '../../../links';
|
import { AssetLink, PartyLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventProps {
|
interface TxDetailsChainEventProps {
|
||||||
deposit: components['schemas']['vegaERC20Deposit'];
|
deposit: components['schemas']['vegaERC20Deposit'];
|
||||||
@@ -36,7 +36,7 @@ export const TxDetailsChainEventDeposit = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Source')}</TableCell>
|
<TableCell>{t('Source')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={deposit.sourceEthereumAddress}
|
id={deposit.sourceEthereumAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { AssetLink } from '../../../links';
|
import { AssetLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventWithdrawalProps {
|
interface TxDetailsChainEventWithdrawalProps {
|
||||||
withdrawal: components['schemas']['vegaERC20Withdrawal'];
|
withdrawal: components['schemas']['vegaERC20Withdrawal'];
|
||||||
@@ -35,7 +35,7 @@ export const TxDetailsChainEventWithdrawal = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Recipient')}</TableCell>
|
<TableCell>{t('Recipient')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={withdrawal.targetEthereumAddress}
|
id={withdrawal.targetEthereumAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { PartyLink } from '../../../links';
|
import { PartyLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventStakeDepositProps {
|
interface TxDetailsChainEventStakeDepositProps {
|
||||||
deposit: components['schemas']['vegaStakeDeposited'];
|
deposit: components['schemas']['vegaStakeDeposited'];
|
||||||
@@ -39,7 +39,7 @@ export const TxDetailsChainEventStakeDeposit = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Source')}</TableCell>
|
<TableCell>{t('Source')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={deposit.ethereumAddress}
|
id={deposit.ethereumAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { PartyLink } from '../../../links';
|
import { PartyLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventStakeRemoveProps {
|
interface TxDetailsChainEventStakeRemoveProps {
|
||||||
remove: components['schemas']['vegaStakeRemoved'];
|
remove: components['schemas']['vegaStakeRemoved'];
|
||||||
@@ -39,7 +39,7 @@ export const TxDetailsChainEventStakeRemove = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Source')}</TableCell>
|
<TableCell>{t('Source')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={remove.ethereumAddress}
|
id={remove.ethereumAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { t } from '@vegaprotocol/i18n';
|
|||||||
import { TableRow, TableCell } from '../../../table';
|
import { TableRow, TableCell } from '../../../table';
|
||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventStakeTotalSupplyProps {
|
interface TxDetailsChainEventStakeTotalSupplyProps {
|
||||||
update: components['schemas']['vegaStakeTotalSupply'];
|
update: components['schemas']['vegaStakeTotalSupply'];
|
||||||
@@ -38,7 +38,7 @@ export const TxDetailsChainEventStakeTotalSupply = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Source')}</TableCell>
|
<TableCell>{t('Source')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={update.tokenAddress}
|
id={update.tokenAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
query ExplorerProposalStatus($id: ID!) {
|
query ExplorerProposalStatus($id: ID!) {
|
||||||
proposal(id: $id) {
|
proposal(id: $id) {
|
||||||
id
|
... on Proposal {
|
||||||
state
|
id
|
||||||
rejectionReason
|
state
|
||||||
|
rejectionReason
|
||||||
|
}
|
||||||
|
... on BatchProposal {
|
||||||
|
id
|
||||||
|
state
|
||||||
|
rejectionReason
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-4
@@ -8,15 +8,22 @@ export type ExplorerProposalStatusQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerProposalStatusQuery = { __typename?: 'Query', proposal?: { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, rejectionReason?: Types.ProposalRejectionReason | null } | null };
|
export type ExplorerProposalStatusQuery = { __typename?: 'Query', proposal?: { __typename?: 'BatchProposal', id?: string | null, state: Types.ProposalState, rejectionReason?: Types.ProposalRejectionReason | null } | { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, rejectionReason?: Types.ProposalRejectionReason | null } | null };
|
||||||
|
|
||||||
|
|
||||||
export const ExplorerProposalStatusDocument = gql`
|
export const ExplorerProposalStatusDocument = gql`
|
||||||
query ExplorerProposalStatus($id: ID!) {
|
query ExplorerProposalStatus($id: ID!) {
|
||||||
proposal(id: $id) {
|
proposal(id: $id) {
|
||||||
id
|
... on Proposal {
|
||||||
state
|
id
|
||||||
rejectionReason
|
state
|
||||||
|
rejectionReason
|
||||||
|
}
|
||||||
|
... on BatchProposal {
|
||||||
|
id
|
||||||
|
state
|
||||||
|
rejectionReason
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -0,0 +1,257 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { BatchItem } from './batch-item';
|
||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
type Item = components['schemas']['vegaBatchProposalTermsChange'];
|
||||||
|
|
||||||
|
describe('BatchItem', () => {
|
||||||
|
it('Renders "Unknown proposal type" by default', () => {
|
||||||
|
const item = {};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Unknown proposal type')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Unknown proposal type" for unknown items', () => {
|
||||||
|
const item = {
|
||||||
|
newLochNessMonster: {
|
||||||
|
location: 'Loch Ness',
|
||||||
|
},
|
||||||
|
} as unknown as Item;
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Unknown proposal type')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "New spot market"', () => {
|
||||||
|
const item = {
|
||||||
|
newSpotMarket: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('New spot market')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Cancel transfer"', () => {
|
||||||
|
const item = {
|
||||||
|
cancelTransfer: {
|
||||||
|
changes: {
|
||||||
|
transferId: 'transfer123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Cancel transfer')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('transf')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Cancel transfer" without an id', () => {
|
||||||
|
const item = {
|
||||||
|
cancelTransfer: {
|
||||||
|
changes: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Cancel transfer')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "New freeform"', () => {
|
||||||
|
const item = {
|
||||||
|
newFreeform: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('New freeform proposal')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "New market"', () => {
|
||||||
|
const item = {
|
||||||
|
newMarket: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('New market')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "New transfer"', () => {
|
||||||
|
const item = {
|
||||||
|
newTransfer: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('New transfer')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update asset" with assetId', () => {
|
||||||
|
const item = {
|
||||||
|
updateAsset: {
|
||||||
|
assetId: 'asset123',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update asset')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('asset123')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update asset" even if assetId is not set', () => {
|
||||||
|
const item = {
|
||||||
|
updateAsset: {
|
||||||
|
assetId: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Update asset')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update market state" with marketId', () => {
|
||||||
|
const item = {
|
||||||
|
updateMarketState: {
|
||||||
|
changes: {
|
||||||
|
marketId: 'market123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update market state')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('market123')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update market state" even if marketId is not set', () => {
|
||||||
|
const item = {
|
||||||
|
updateMarketState: {
|
||||||
|
changes: {
|
||||||
|
marketId: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update market state')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update network parameter" with parameter', () => {
|
||||||
|
const item = {
|
||||||
|
updateNetworkParameter: {
|
||||||
|
changes: {
|
||||||
|
key: 'parameter123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MockedProvider>
|
||||||
|
<MemoryRouter>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MemoryRouter>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update network parameter')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('parameter123')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update network parameter" even if parameter is not set', () => {
|
||||||
|
const item = {
|
||||||
|
updateNetworkParameter: {
|
||||||
|
changes: {
|
||||||
|
key: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Update network parameter')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update referral program"', () => {
|
||||||
|
const item = {
|
||||||
|
updateReferralProgram: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Update referral program')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update spot market" with marketId', () => {
|
||||||
|
const item = {
|
||||||
|
updateSpotMarket: {
|
||||||
|
marketId: 'market123',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update spot market')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('market123')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update spot market" even if marketId is not set', () => {
|
||||||
|
const item = {
|
||||||
|
updateSpotMarket: {
|
||||||
|
marketId: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update spot market')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
it('Renders "Update market" with marketId', () => {
|
||||||
|
const item = {
|
||||||
|
updateMarket: {
|
||||||
|
marketId: 'market123',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update market')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('market123')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update market" even if marketId is not set', () => {
|
||||||
|
const item = {
|
||||||
|
updateMarket: {
|
||||||
|
marketId: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update market')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update volume discount program"', () => {
|
||||||
|
const item = {
|
||||||
|
updateVolumeDiscountProgram: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(
|
||||||
|
screen.getByText('Update volume discount program')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { AssetLink, MarketLink, NetworkParameterLink } from '../../../links';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import Hash from '../../../links/hash';
|
||||||
|
|
||||||
|
type Item = components['schemas']['vegaBatchProposalTermsChange'];
|
||||||
|
|
||||||
|
export interface BatchItemProps {
|
||||||
|
item: Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces a one line summary for an item in a batch proposal. Could
|
||||||
|
* easily be adapted to summarise individual proposals, but there is no
|
||||||
|
* place for that yet.
|
||||||
|
*
|
||||||
|
* Details (like IDs) should be shown and linked if available, but handled
|
||||||
|
* if not available. This is adequate as the ProposalSummary component contains
|
||||||
|
* a JSON viewer for the full proposal.
|
||||||
|
*/
|
||||||
|
export const BatchItem = ({ item }: BatchItemProps) => {
|
||||||
|
if (item.cancelTransfer) {
|
||||||
|
const transferId = item?.cancelTransfer?.changes?.transferId || false;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Cancel transfer')}
|
||||||
|
{transferId && (
|
||||||
|
<Hash className="ml-1" truncate={true} text={transferId} />
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.newFreeform) {
|
||||||
|
return <span>{t('New freeform proposal')}</span>;
|
||||||
|
} else if (item.newMarket) {
|
||||||
|
return <span>{t('New market')}</span>;
|
||||||
|
} else if (item.newSpotMarket) {
|
||||||
|
return <span>{t('New spot market')}</span>;
|
||||||
|
} else if (item.newTransfer) {
|
||||||
|
return <span>{t('New transfer')}</span>;
|
||||||
|
} else if (item.updateAsset) {
|
||||||
|
const assetId = item?.updateAsset?.assetId || false;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Update asset')}
|
||||||
|
{assetId && <AssetLink className="ml-1" assetId={assetId} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.updateMarket) {
|
||||||
|
const marketId = item?.updateMarket?.marketId || false;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Update market')}{' '}
|
||||||
|
{marketId && <MarketLink className="ml-1" id={marketId} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.updateMarketState) {
|
||||||
|
const marketId = item?.updateMarketState?.changes?.marketId || false;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Update market state')}
|
||||||
|
{marketId && <MarketLink className="ml-1" id={marketId} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.updateNetworkParameter) {
|
||||||
|
const param = item?.updateNetworkParameter?.changes?.key || false;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Update network parameter')}
|
||||||
|
{param && <NetworkParameterLink className="ml-1" parameter={param} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.updateReferralProgram) {
|
||||||
|
return <span>{t('Update referral program')}</span>;
|
||||||
|
} else if (item.updateSpotMarket) {
|
||||||
|
const marketId = item?.updateSpotMarket?.marketId || '';
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Update spot market')}
|
||||||
|
<MarketLink className="ml-1" id={marketId} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.updateVolumeDiscountProgram) {
|
||||||
|
return <span>{t('Update volume discount program')}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <span>{t('Unknown proposal type')}</span>;
|
||||||
|
};
|
||||||
@@ -14,16 +14,18 @@ export function format(date: string | undefined, def: string) {
|
|||||||
return new Date().toLocaleDateString() || def;
|
return new Date().toLocaleDateString() || def;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDate(
|
type Proposal = Extract<
|
||||||
data: ExplorerProposalStatusQuery | undefined,
|
ExplorerProposalStatusQuery['proposal'],
|
||||||
terms: Terms
|
{ __typename?: 'Proposal' }
|
||||||
): string {
|
>;
|
||||||
|
|
||||||
|
export function getDate(proposal: Proposal | undefined, terms: Terms): string {
|
||||||
const DEFAULT = t('Unknown');
|
const DEFAULT = t('Unknown');
|
||||||
if (!data?.proposal?.state) {
|
if (!proposal?.state) {
|
||||||
return DEFAULT;
|
return DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data.proposal.state) {
|
switch (proposal.state) {
|
||||||
case 'STATE_DECLINED':
|
case 'STATE_DECLINED':
|
||||||
return `${t('Rejected on')}: ${format(terms.closingTimestamp, DEFAULT)}`;
|
return `${t('Rejected on')}: ${format(terms.closingTimestamp, DEFAULT)}`;
|
||||||
case 'STATE_ENACTED':
|
case 'STATE_ENACTED':
|
||||||
@@ -62,9 +64,11 @@ export const ProposalDate = ({ terms, id }: ProposalDateProps) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const proposal = data?.proposal as Proposal;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Lozenge className="font-sans text-xs float-right">
|
<Lozenge className="font-sans text-xs float-right">
|
||||||
{getDate(data, terms)}
|
{getDate(proposal, terms)}
|
||||||
</Lozenge>
|
</Lozenge>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,17 +2,8 @@ import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
|||||||
import type { IconProps } from '@vegaprotocol/ui-toolkit';
|
import type { IconProps } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useExplorerProposalStatusQuery } from './__generated__/Proposal';
|
import { useExplorerProposalStatusQuery } from './__generated__/Proposal';
|
||||||
import type { ExplorerProposalStatusQuery } from './__generated__/Proposal';
|
import type { ExplorerProposalStatusQuery } from './__generated__/Proposal';
|
||||||
import type * as Apollo from '@apollo/client';
|
|
||||||
import type * as Types from '@vegaprotocol/types';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
type ProposalQueryResult = Apollo.QueryResult<
|
|
||||||
ExplorerProposalStatusQuery,
|
|
||||||
Types.Exact<{
|
|
||||||
id: string;
|
|
||||||
}>
|
|
||||||
>;
|
|
||||||
|
|
||||||
interface ProposalStatusIconProps {
|
interface ProposalStatusIconProps {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
@@ -29,29 +20,38 @@ type IconAndLabel = {
|
|||||||
* @param data a data result from useExplorerProposalStatusQuery
|
* @param data a data result from useExplorerProposalStatusQuery
|
||||||
* @returns Icon name
|
* @returns Icon name
|
||||||
*/
|
*/
|
||||||
export function getIconAndLabelForStatus(
|
export function useIconAndLabelForStatus(id: string): IconAndLabel {
|
||||||
res: ProposalQueryResult
|
const { data, loading, error } = useExplorerProposalStatusQuery({
|
||||||
): IconAndLabel {
|
variables: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const proposal = data?.proposal as Extract<
|
||||||
|
ExplorerProposalStatusQuery['proposal'],
|
||||||
|
{ __typename?: 'Proposal' }
|
||||||
|
>;
|
||||||
|
|
||||||
const DEFAULT: IconAndLabel = {
|
const DEFAULT: IconAndLabel = {
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
label: t('Proposal state unknown'),
|
label: t('Proposal state unknown'),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (res.loading) {
|
if (loading) {
|
||||||
return {
|
return {
|
||||||
icon: 'more',
|
icon: 'more',
|
||||||
label: t('Loading data'),
|
label: t('Loading data'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res?.data?.proposal || res.error) {
|
if (!data?.proposal || error) {
|
||||||
return {
|
return {
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
label: res.error?.message || DEFAULT.label,
|
label: error?.message || DEFAULT.label,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (res.data.proposal.state) {
|
switch (proposal.state) {
|
||||||
case 'STATE_DECLINED':
|
case 'STATE_DECLINED':
|
||||||
return {
|
return {
|
||||||
icon: 'stop',
|
icon: 'stop',
|
||||||
@@ -99,13 +99,7 @@ export function getIconAndLabelForStatus(
|
|||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export const ProposalStatusIcon = ({ id }: ProposalStatusIconProps) => {
|
export const ProposalStatusIcon = ({ id }: ProposalStatusIconProps) => {
|
||||||
const { icon, label } = getIconAndLabelForStatus(
|
const { icon, label } = useIconAndLabelForStatus(id);
|
||||||
useExplorerProposalStatusQuery({
|
|
||||||
variables: {
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="float-left mr-3">
|
<div className="float-left mr-3">
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import type { ProposalTerms } from '../tx-proposal';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import type { components } from '../../../../../types/explorer';
|
|
||||||
import { JsonViewerDialog } from '../../../dialogs/json-viewer-dialog';
|
import { JsonViewerDialog } from '../../../dialogs/json-viewer-dialog';
|
||||||
import ProposalLink from '../../../links/proposal-link/proposal-link';
|
import ProposalLink from '../../../links/proposal-link/proposal-link';
|
||||||
import truncate from 'lodash/truncate';
|
import truncate from 'lodash/truncate';
|
||||||
@@ -9,7 +7,12 @@ import ReactMarkdown from 'react-markdown';
|
|||||||
import { ProposalDate } from './proposal-date';
|
import { ProposalDate } from './proposal-date';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
import type { ProposalTerms } from '../tx-proposal';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import { BatchItem } from './batch-item';
|
||||||
|
|
||||||
type Rationale = components['schemas']['vegaProposalRationale'];
|
type Rationale = components['schemas']['vegaProposalRationale'];
|
||||||
|
type Batch = components['schemas']['v1BatchProposalSubmissionTerms']['changes'];
|
||||||
|
|
||||||
type ProposalTermsDialog = {
|
type ProposalTermsDialog = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -21,6 +24,7 @@ interface ProposalSummaryProps {
|
|||||||
id: string;
|
id: string;
|
||||||
rationale?: Rationale;
|
rationale?: Rationale;
|
||||||
terms?: ProposalTerms;
|
terms?: ProposalTerms;
|
||||||
|
batch?: Batch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,6 +35,7 @@ export const ProposalSummary = ({
|
|||||||
id,
|
id,
|
||||||
rationale,
|
rationale,
|
||||||
terms,
|
terms,
|
||||||
|
batch,
|
||||||
}: ProposalSummaryProps) => {
|
}: ProposalSummaryProps) => {
|
||||||
const [dialog, setDialog] = useState<ProposalTermsDialog>({
|
const [dialog, setDialog] = useState<ProposalTermsDialog>({
|
||||||
open: false,
|
open: false,
|
||||||
@@ -72,6 +77,18 @@ export const ProposalSummary = ({
|
|||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{batch && (
|
||||||
|
<section className="pt-2 text-sm leading-tight my-3">
|
||||||
|
<h2 className="text-lg pb-1">{t('Changes')}</h2>
|
||||||
|
<ol>
|
||||||
|
{batch.map((change, index) => (
|
||||||
|
<li className="ml-4 list-decimal" key={`batch-${index}`}>
|
||||||
|
<BatchItem item={change} />
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
<div className="pt-5">
|
<div className="pt-5">
|
||||||
<button className="underline max-md:hidden mr-5" onClick={openDialog}>
|
<button className="underline max-md:hidden mr-5" onClick={openDialog}>
|
||||||
{t('View terms')}
|
{t('View terms')}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { TxDetailsShared } from '../shared/tx-details-shared';
|
||||||
|
import { TableWithTbody } from '../../../table';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TableCell, TableRow } from '../../../table';
|
||||||
|
|
||||||
|
type Update = components['schemas']['v1UpdatePartyProfile'];
|
||||||
|
|
||||||
|
interface TxDetailsUpdatePartyProfileProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Party profiles can be an alias and arbitrary key/values pairs.
|
||||||
|
* This component displays the alias, if any, but not the metadata. When there is
|
||||||
|
* some wider usage, we can decide how to render it. For now, it's available in the
|
||||||
|
* full TX details.
|
||||||
|
*/
|
||||||
|
export const TxDetailsUpdatePartyProfile = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsUpdatePartyProfileProps) => {
|
||||||
|
if (!txData?.command.updatePartyProfile) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const update: Update = txData.command.updatePartyProfile;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
|
||||||
|
{update.alias && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('New alias')}</TableCell>
|
||||||
|
<TableCell>{update.alias}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableWithTbody>
|
||||||
|
);
|
||||||
|
};
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type ExplorerReferralCodeOwnerQueryVariables = Types.Exact<{
|
||||||
|
id: Types.Scalars['ID'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ExplorerReferralCodeOwnerQuery = { __typename?: 'Query', referralSets: { __typename?: 'ReferralSetConnection', edges: Array<{ __typename?: 'ReferralSetEdge', node: { __typename?: 'ReferralSet', createdAt: any, updatedAt: any, referrer: string } } | null> } };
|
||||||
|
|
||||||
|
|
||||||
|
export const ExplorerReferralCodeOwnerDocument = gql`
|
||||||
|
query ExplorerReferralCodeOwner($id: ID!) {
|
||||||
|
referralSets(id: $id) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
referrer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useExplorerReferralCodeOwnerQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useExplorerReferralCodeOwnerQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useExplorerReferralCodeOwnerQuery` 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 } = useExplorerReferralCodeOwnerQuery({
|
||||||
|
* variables: {
|
||||||
|
* id: // value for 'id'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useExplorerReferralCodeOwnerQuery(baseOptions: Apollo.QueryHookOptions<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>(ExplorerReferralCodeOwnerDocument, options);
|
||||||
|
}
|
||||||
|
export function useExplorerReferralCodeOwnerLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>(ExplorerReferralCodeOwnerDocument, options);
|
||||||
|
}
|
||||||
|
export type ExplorerReferralCodeOwnerQueryHookResult = ReturnType<typeof useExplorerReferralCodeOwnerQuery>;
|
||||||
|
export type ExplorerReferralCodeOwnerLazyQueryHookResult = ReturnType<typeof useExplorerReferralCodeOwnerLazyQuery>;
|
||||||
|
export type ExplorerReferralCodeOwnerQueryResult = Apollo.QueryResult<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
query ExplorerReferralCodeOwner($id: ID!) {
|
||||||
|
referralSets(id: $id) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
referrer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
import { render, waitFor } from '@testing-library/react';
|
||||||
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
import { ReferralCodeOwner } from './referral-code-owner';
|
||||||
|
import type { ReferralCodeOwnerProps } from './referral-code-owner';
|
||||||
|
import { ExplorerReferralCodeOwnerDocument } from './__generated__/code-owner';
|
||||||
|
const renderComponent = (
|
||||||
|
props: ReferralCodeOwnerProps,
|
||||||
|
mocks: MockedResponse[]
|
||||||
|
) => {
|
||||||
|
return render(
|
||||||
|
<MockedProvider mocks={mocks}>
|
||||||
|
<MemoryRouter>
|
||||||
|
<ReferralCodeOwner {...props} />
|
||||||
|
</MemoryRouter>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('ReferralCodeOwner', () => {
|
||||||
|
it('should render loading state', () => {
|
||||||
|
const mocks = [
|
||||||
|
{
|
||||||
|
request: {
|
||||||
|
query: ExplorerReferralCodeOwnerDocument,
|
||||||
|
variables: {
|
||||||
|
id: 'ABC123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
||||||
|
|
||||||
|
expect(getByText('Loading...')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render error state', async () => {
|
||||||
|
const errorMessage = 'Error fetching referrer: ABC123';
|
||||||
|
const mocks = [
|
||||||
|
{
|
||||||
|
request: {
|
||||||
|
query: ExplorerReferralCodeOwnerDocument,
|
||||||
|
variables: {
|
||||||
|
id: 'ABC123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
error: new Error('nope'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(getByText(errorMessage)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render link to referring party', async () => {
|
||||||
|
const referrerId = 'DEF789';
|
||||||
|
|
||||||
|
const mocks = [
|
||||||
|
{
|
||||||
|
request: {
|
||||||
|
query: ExplorerReferralCodeOwnerDocument,
|
||||||
|
variables: {
|
||||||
|
id: 'ABC123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
referralSets: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
__typename: 'ReferralSet',
|
||||||
|
referrer: referrerId,
|
||||||
|
createdAt: '123',
|
||||||
|
updatedAt: '456',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(getByText(referrerId)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { TableCell } from '../../../table';
|
||||||
|
import { useExplorerReferralCodeOwnerQuery } from './__generated__/code-owner';
|
||||||
|
import { PartyLink } from '../../../links';
|
||||||
|
|
||||||
|
export interface ReferralCodeOwnerProps {
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the owner of a referral code
|
||||||
|
*/
|
||||||
|
export const ReferralCodeOwner = ({ code }: ReferralCodeOwnerProps) => {
|
||||||
|
const { data, error, loading } = useExplorerReferralCodeOwnerQuery({
|
||||||
|
variables: {
|
||||||
|
id: code,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const referrer = data?.referralSets.edges[0]?.node.referrer || '';
|
||||||
|
return (
|
||||||
|
<TableCell>
|
||||||
|
{loading && 'Loading...'}
|
||||||
|
{error && `Error fetching referrer: ${code}`}
|
||||||
|
{referrer.length > 0 && <PartyLink id={referrer} />}
|
||||||
|
</TableCell>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { ReferralTeam } from './team';
|
||||||
|
import type { CreateReferralSet } from './team';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
|
||||||
|
describe('ReferralTeam', () => {
|
||||||
|
const team = {
|
||||||
|
name: 'Test Team',
|
||||||
|
teamUrl: 'https://example.com/team',
|
||||||
|
avatarUrl: 'https://example.com/avatar',
|
||||||
|
closed: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockTx: CreateReferralSet = {
|
||||||
|
team,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockId = '123456';
|
||||||
|
const mockCreator = 'JohnDoe';
|
||||||
|
|
||||||
|
it('should render the team name', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByText('Test Team')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the team ID', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByText('Id')).toBeInTheDocument();
|
||||||
|
expect(getByText(mockId)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the creator', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByText('Creator')).toBeInTheDocument();
|
||||||
|
expect(getByText(mockCreator)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the team URL', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByText('Team URL')).toBeInTheDocument();
|
||||||
|
expect(getByText(team.teamUrl)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the avatar URL', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByText('Avatar')).toBeInTheDocument();
|
||||||
|
expect(getByText(team.avatarUrl)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the open status as a tick if closed is falsy', () => {
|
||||||
|
const { getByTestId } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByTestId('open-yes')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the open status as a cross if it is truthy', () => {
|
||||||
|
const m = {
|
||||||
|
team: {
|
||||||
|
closed: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const { getByTestId } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={m} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByTestId('open-no')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import {
|
||||||
|
VegaIcon,
|
||||||
|
Icon,
|
||||||
|
KeyValueTable,
|
||||||
|
KeyValueTableRow,
|
||||||
|
VegaIconNames,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import Hash from '../../../links/hash';
|
||||||
|
import { t } from 'i18next';
|
||||||
|
import { PartyLink } from '../../../links';
|
||||||
|
|
||||||
|
export type CreateReferralSet = components['schemas']['v1CreateReferralSet'];
|
||||||
|
export type ReferralTeam = CreateReferralSet['team'];
|
||||||
|
|
||||||
|
export interface ReferralTeamProps {
|
||||||
|
tx: CreateReferralSet;
|
||||||
|
id: string;
|
||||||
|
creator: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the details for a team in a CreateReferralSet or UpdateReferralSet transaction.
|
||||||
|
*
|
||||||
|
* Intentionally does not render the avatar image or link to the team url.
|
||||||
|
*/
|
||||||
|
export const ReferralTeam = ({ tx, id, creator }: ReferralTeamProps) => {
|
||||||
|
if (!tx.team) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<div className="inline-block mr-2 leading-none">
|
||||||
|
<VegaIcon name={VegaIconNames.TEAM} />
|
||||||
|
</div>
|
||||||
|
{tx.team.name && (
|
||||||
|
<h3 className="inline-block leading-loose">{tx.team.name}</h3>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="min-w-fit max-w-2xl block">
|
||||||
|
<KeyValueTable>
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('Id')}
|
||||||
|
<Hash text={id} truncate={false} />
|
||||||
|
</KeyValueTableRow>
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('Creator')}
|
||||||
|
<PartyLink id={creator} truncate={false} />
|
||||||
|
</KeyValueTableRow>
|
||||||
|
{tx.team.teamUrl && (
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('Team URL')}
|
||||||
|
<Hash text={tx.team.teamUrl} truncate={false} />
|
||||||
|
</KeyValueTableRow>
|
||||||
|
)}
|
||||||
|
{tx.team.avatarUrl && (
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('Avatar')}
|
||||||
|
<Hash text={tx.team.avatarUrl} truncate={false} />
|
||||||
|
</KeyValueTableRow>
|
||||||
|
)}
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('Open')}
|
||||||
|
<span data-testid={!tx.team.closed ? 'open-yes' : 'open-no'}>
|
||||||
|
{!tx.team.closed ? <Icon name="tick" /> : <Icon name="cross" />}
|
||||||
|
</span>
|
||||||
|
</KeyValueTableRow>
|
||||||
|
</KeyValueTable>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -27,7 +27,8 @@ export const sharedHeaderProps = {
|
|||||||
className: 'align-top',
|
className: 'align-top',
|
||||||
};
|
};
|
||||||
|
|
||||||
const Labels: Record<BlockExplorerTransactionResult['type'], string> = {
|
// The incoming type field is usually the right thing to show. Exceptions are listed here
|
||||||
|
const LabelOverrides: Record<BlockExplorerTransactionResult['type'], string> = {
|
||||||
'Stop Orders Submission': 'Stop Order',
|
'Stop Orders Submission': 'Stop Order',
|
||||||
'Stop Orders Cancellation': 'Cancel Stop Order',
|
'Stop Orders Cancellation': 'Cancel Stop Order',
|
||||||
};
|
};
|
||||||
@@ -50,7 +51,7 @@ 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;
|
const type = LabelOverrides[txData.type] || txData.type;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ const AccountType: Record<AccountTypes, string> = {
|
|||||||
ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY: 'Reward Return Volatility',
|
ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY: 'Reward Return Volatility',
|
||||||
ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING: 'Reward Validator Ranking',
|
ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING: 'Reward Validator Ranking',
|
||||||
ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD: 'Pending Fee Referral Reward',
|
ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD: 'Pending Fee Referral Reward',
|
||||||
|
ACCOUNT_TYPE_ORDER_MARGIN: 'Order Margin',
|
||||||
};
|
};
|
||||||
|
|
||||||
interface TransferParticipantsProps {
|
interface TransferParticipantsProps {
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import { ReferralCodeOwner } from './referrals/referral-code-owner';
|
||||||
|
|
||||||
|
interface TxDetailsApplyReferralCodeProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
||||||
|
*/
|
||||||
|
export const TxDetailsApplyReferralCode = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsApplyReferralCodeProps) => {
|
||||||
|
if (!txData || !txData.command.applyReferralCode || !txData.signature) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const referralCode = txData.command.applyReferralCode.id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared
|
||||||
|
txData={txData}
|
||||||
|
pubKey={pubKey}
|
||||||
|
blockData={blockData}
|
||||||
|
/>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Applied Code')}</TableCell>
|
||||||
|
<TableCell>{referralCode}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Referrer')}</TableCell>
|
||||||
|
<ReferralCodeOwner code={referralCode} />
|
||||||
|
</TableRow>
|
||||||
|
</TableWithTbody>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { sharedHeaderProps, TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import type { components } from '../../../../types/explorer';
|
||||||
|
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||||
|
import { ProposalSummary } from './proposal/summary';
|
||||||
|
import Hash from '../../links/hash';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
export type Proposal = components['schemas']['v1BatchProposalSubmission'];
|
||||||
|
export type ProposalTerms = components['schemas']['vegaProposalTerms'];
|
||||||
|
|
||||||
|
interface TxBatchProposalProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const TxBatchProposal = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxBatchProposalProps) => {
|
||||||
|
if (!txData || !txData.command.batchProposalSubmission) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
let deterministicId = '';
|
||||||
|
|
||||||
|
const proposal: Proposal = txData.command.batchProposalSubmission;
|
||||||
|
const sig = txData?.signature?.value;
|
||||||
|
if (sig) {
|
||||||
|
deterministicId = txSignatureToDeterministicId(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell {...sharedHeaderProps}>{t('Type')}</TableCell>
|
||||||
|
<TableCell>{t('Batch proposal')}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TxDetailsShared
|
||||||
|
txData={txData}
|
||||||
|
pubKey={pubKey}
|
||||||
|
blockData={blockData}
|
||||||
|
hideTypeRow={true}
|
||||||
|
/>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Batch size')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{proposal.terms?.changes?.length || t('No changes')}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Proposal ID')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Hash text={deterministicId} />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableWithTbody>
|
||||||
|
{proposal && (
|
||||||
|
<ProposalSummary
|
||||||
|
id={deterministicId}
|
||||||
|
rationale={proposal?.rationale}
|
||||||
|
terms={proposal.terms}
|
||||||
|
batch={proposal.terms?.changes}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||||
|
import { ReferralTeam } from './referrals/team';
|
||||||
|
|
||||||
|
interface TxDetailsCreateReferralProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
||||||
|
*/
|
||||||
|
export const TxDetailsCreateReferralSet = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsCreateReferralProps) => {
|
||||||
|
if (!txData || !txData.command.createReferralSet || !txData.signature) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = txSignatureToDeterministicId(txData.signature.value);
|
||||||
|
|
||||||
|
const isTeam = txData.command.createReferralSet.isTeam || false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared
|
||||||
|
txData={txData}
|
||||||
|
pubKey={pubKey}
|
||||||
|
blockData={blockData}
|
||||||
|
/>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{isTeam ? t('Team ID') : t('Referral code')}</TableCell>
|
||||||
|
<TableCell>{id}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableWithTbody>
|
||||||
|
|
||||||
|
<ReferralTeam
|
||||||
|
tx={txData.command.createReferralSet}
|
||||||
|
id={id}
|
||||||
|
creator={txData.submitter}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -28,6 +28,13 @@ import { TxProposal } from './tx-proposal';
|
|||||||
import { TxDetailsTransfer } from './tx-transfer';
|
import { TxDetailsTransfer } from './tx-transfer';
|
||||||
import { TxDetailsStopOrderSubmission } from './tx-stop-order-submission';
|
import { TxDetailsStopOrderSubmission } from './tx-stop-order-submission';
|
||||||
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
|
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
|
||||||
|
import { TxDetailsCreateReferralSet } from './tx-create-referral-set';
|
||||||
|
import { TxDetailsApplyReferralCode } from './tx-apply-referral-code';
|
||||||
|
import { TxDetailsUpdateReferralSet } from './tx-update-referral-set';
|
||||||
|
import { TxDetailsJoinTeam } from './tx-join-team';
|
||||||
|
import { TxDetailsUpdateMarginMode } from './tx-update-margin-mode';
|
||||||
|
import { TxBatchProposal } from './tx-batch-proposal';
|
||||||
|
import { TxDetailsUpdatePartyProfile } from './proposal/tx-update-party-profile';
|
||||||
|
|
||||||
interface TxDetailsWrapperProps {
|
interface TxDetailsWrapperProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -121,6 +128,20 @@ function getTransactionComponent(txData?: BlockExplorerTransactionResult) {
|
|||||||
return TxDetailsStopOrderSubmission;
|
return TxDetailsStopOrderSubmission;
|
||||||
case 'Transfer Funds':
|
case 'Transfer Funds':
|
||||||
return TxDetailsTransfer;
|
return TxDetailsTransfer;
|
||||||
|
case 'Create Referral Set':
|
||||||
|
return TxDetailsCreateReferralSet;
|
||||||
|
case 'Update Referral Set':
|
||||||
|
return TxDetailsUpdateReferralSet;
|
||||||
|
case 'Apply Referral Code':
|
||||||
|
return TxDetailsApplyReferralCode;
|
||||||
|
case 'Join Team':
|
||||||
|
return TxDetailsJoinTeam;
|
||||||
|
case 'Update Margin Mode':
|
||||||
|
return TxDetailsUpdateMarginMode;
|
||||||
|
case 'Batch Proposal':
|
||||||
|
return TxBatchProposal;
|
||||||
|
case 'Update Party Profile':
|
||||||
|
return TxDetailsUpdatePartyProfile;
|
||||||
default:
|
default:
|
||||||
return TxDetailsGeneric;
|
return TxDetailsGeneric;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { TxDetailsShared } from './shared/tx-details-shared';
|
|||||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../links/external-explorer-link/external-explorer-link';
|
||||||
import { BlockLink } from '../../links';
|
import { BlockLink } from '../../links';
|
||||||
|
|
||||||
type EthKeyRotate = components['schemas']['v1EthereumKeyRotateSubmission'];
|
type EthKeyRotate = components['schemas']['v1EthereumKeyRotateSubmission'];
|
||||||
@@ -46,7 +46,7 @@ export const TxDetailsEthKeyRotate = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Old Address')}</TableCell>
|
<TableCell>{t('Old Address')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
id={k.currentAddress}
|
id={k.currentAddress}
|
||||||
/>
|
/>
|
||||||
@@ -57,7 +57,7 @@ export const TxDetailsEthKeyRotate = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('New Address')}</TableCell>
|
<TableCell>{t('New Address')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
id={k.newAddress}
|
id={k.newAddress}
|
||||||
/>
|
/>
|
||||||
@@ -68,7 +68,7 @@ export const TxDetailsEthKeyRotate = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Submitter address')}</TableCell>
|
<TableCell>{t('Submitter address')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
id={k.submitterAddress}
|
id={k.submitterAddress}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import { TableRow, TableCell, TableWithTbody } from '../../table';
|
|||||||
|
|
||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../links/external-explorer-link/external-explorer-link';
|
||||||
import { NodeLink } from '../../links';
|
import { NodeLink } from '../../links';
|
||||||
|
|
||||||
type Command = components['schemas']['v1IssueSignatures'];
|
type Command = components['schemas']['v1IssueSignatures'];
|
||||||
@@ -57,7 +57,7 @@ export const TxDetailsIssueSignatures = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('ETH key')}</TableCell>
|
<TableCell>{t('ETH key')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={cmd.submitter}
|
id={cmd.submitter}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import { ReferralCodeOwner } from './referrals/referral-code-owner';
|
||||||
|
|
||||||
|
interface TxDetailsJoinTeamProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
||||||
|
*/
|
||||||
|
export const TxDetailsJoinTeam = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsJoinTeamProps) => {
|
||||||
|
if (!txData || !txData.command.joinTeam || !txData.signature) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const team = txData.command.joinTeam.id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared
|
||||||
|
txData={txData}
|
||||||
|
pubKey={pubKey}
|
||||||
|
blockData={blockData}
|
||||||
|
/>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Team')}</TableCell>
|
||||||
|
<TableCell>{team}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Referrer')}</TableCell>
|
||||||
|
<ReferralCodeOwner code={team} />
|
||||||
|
</TableRow>
|
||||||
|
</TableWithTbody>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -6,9 +6,9 @@ import { TableRow, TableCell, TableWithTbody } from '../../table';
|
|||||||
|
|
||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../links/external-explorer-link/external-explorer-link';
|
||||||
import { PartyLink } from '../../links';
|
import { PartyLink } from '../../links';
|
||||||
import Hash from '../../links/hash';
|
import Hash from '../../links/hash';
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
@@ -72,7 +72,7 @@ export const TxDetailsNodeAnnounce = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Ethereum Address')}</TableCell>
|
<TableCell>{t('Ethereum Address')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
id={cmd.ethereumAddress}
|
id={cmd.ethereumAddress}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import { useExplorerNodeVoteQuery } from './__generated__/Node-vote';
|
|||||||
import { PartyLink } from '../../links';
|
import { PartyLink } from '../../links';
|
||||||
import { Time } from '../../time';
|
import { Time } from '../../time';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsNodeVoteProps {
|
interface TxDetailsNodeVoteProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -143,7 +143,7 @@ export function TxHash({ hash }: TxDetailsEthTxHashProps) {
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>Ethereum TX:</TableCell>
|
<TableCell>Ethereum TX:</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink id={hash} type={EthExplorerLinkTypes.tx} />
|
<ExternalExplorerLink id={hash} type={EthExplorerLinkTypes.tx} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import GovernanceAssetBalance from '../../asset-balance/governance-asset-balance
|
|||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
|
|
||||||
export const methodText: Record<
|
export const methodText: Record<
|
||||||
components['schemas']['UndelegateSubmissionMethod'],
|
components['schemas']['v1UndelegateSubmissionMethod'],
|
||||||
string
|
string
|
||||||
> = {
|
> = {
|
||||||
METHOD_NOW: 'Immediate',
|
METHOD_NOW: 'Immediate',
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import type { components } from '../../../../types/explorer';
|
||||||
|
import { MarketLink } from '../../links';
|
||||||
|
|
||||||
|
interface TxDetailsUpdateMarginModeProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mode = components['schemas']['UpdateMarginModeMode'];
|
||||||
|
|
||||||
|
const MarginModeLabels: Record<Mode, string> = {
|
||||||
|
MODE_CROSS_MARGIN: t('Cross margin'),
|
||||||
|
MODE_ISOLATED_MARGIN: t('Isolated margin'),
|
||||||
|
MODE_UNSPECIFIED: t('Unspecified'),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TxDetailsUpdateMarginMode = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsUpdateMarginModeProps) => {
|
||||||
|
if (!txData || !txData.command.updateMarginMode) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u: components['schemas']['v1UpdateMarginMode'] =
|
||||||
|
txData.command.updateMarginMode;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
|
||||||
|
{u.marketId && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Market ID')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<MarketLink id={u.marketId} />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
{u.mode && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('New margin mode')}</TableCell>
|
||||||
|
<TableCell>{MarginModeLabels[u.mode]}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
{u.marginFactor && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Margin factor')}</TableCell>
|
||||||
|
<TableCell>{u.marginFactor}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableWithTbody>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||||
|
import { ReferralTeam } from './referrals/team';
|
||||||
|
|
||||||
|
interface TxDetailsUpdateReferralProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A copy of create referral set, effectively.
|
||||||
|
* Updating a referral set without a team doesn't make sense,
|
||||||
|
* but is valid, so this component ignores sense.
|
||||||
|
*/
|
||||||
|
export const TxDetailsUpdateReferralSet = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsUpdateReferralProps) => {
|
||||||
|
if (!txData || !txData.command.updateReferralSet || !txData.signature) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = txSignatureToDeterministicId(txData.signature.value);
|
||||||
|
|
||||||
|
const isTeam = txData.command.updateReferralSet.isTeam || false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared
|
||||||
|
txData={txData}
|
||||||
|
pubKey={pubKey}
|
||||||
|
blockData={blockData}
|
||||||
|
/>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{isTeam ? t('Team ID') : t('Referral code')}</TableCell>
|
||||||
|
<TableCell>{id}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableWithTbody>
|
||||||
|
|
||||||
|
<ReferralTeam
|
||||||
|
tx={txData.command.updateReferralSet}
|
||||||
|
id={id}
|
||||||
|
creator={txData.submitter}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -4,9 +4,9 @@ import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint
|
|||||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../links/external-explorer-link/external-explorer-link';
|
||||||
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||||
import AssetBalance from '../../asset-balance/asset-balance';
|
import AssetBalance from '../../asset-balance/asset-balance';
|
||||||
import { useScrollToLocation } from '../../../hooks/scroll-to-location';
|
import { useScrollToLocation } from '../../../hooks/scroll-to-location';
|
||||||
@@ -57,7 +57,7 @@ export const TxDetailsWithdrawSubmission = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Recipient')}</TableCell>
|
<TableCell>{t('Recipient')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={w.ext.erc20.receiverAddress}
|
id={w.ext.erc20.receiverAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export type FilterOption =
|
|||||||
| 'Amend Order'
|
| 'Amend Order'
|
||||||
| 'Apply Referral Code'
|
| 'Apply Referral Code'
|
||||||
| 'Batch Market Instructions'
|
| 'Batch Market Instructions'
|
||||||
|
| 'Batch Proposal'
|
||||||
| 'Cancel LiquidityProvision Order'
|
| 'Cancel LiquidityProvision Order'
|
||||||
| 'Cancel Order'
|
| 'Cancel Order'
|
||||||
| 'Cancel Transfer Funds'
|
| 'Cancel Transfer Funds'
|
||||||
@@ -28,6 +29,7 @@ export type FilterOption =
|
|||||||
| 'Delegate'
|
| 'Delegate'
|
||||||
| 'Ethereum Key Rotate Submission'
|
| 'Ethereum Key Rotate Submission'
|
||||||
| 'Issue Signatures'
|
| 'Issue Signatures'
|
||||||
|
| 'Join Team'
|
||||||
| 'Key Rotate Submission'
|
| 'Key Rotate Submission'
|
||||||
| 'Liquidity Provision Order'
|
| 'Liquidity Provision Order'
|
||||||
| 'Node Signature'
|
| 'Node Signature'
|
||||||
@@ -42,50 +44,61 @@ export type FilterOption =
|
|||||||
| 'Submit Order'
|
| 'Submit Order'
|
||||||
| 'Transfer Funds'
|
| 'Transfer Funds'
|
||||||
| 'Undelegate'
|
| 'Undelegate'
|
||||||
|
| 'Update Party Profile'
|
||||||
| 'Update Referral Set'
|
| 'Update Referral Set'
|
||||||
|
| 'Update Margin Mode'
|
||||||
| 'Validator Heartbeat'
|
| 'Validator Heartbeat'
|
||||||
| 'Vote on Proposal'
|
| 'Vote on Proposal'
|
||||||
| 'Withdraw';
|
| 'Withdraw';
|
||||||
|
|
||||||
// Alphabetised list of transaction types to appear at the top level
|
export const filterOptions: Record<string, FilterOption[]> = {
|
||||||
export const PrimaryFilterOptions: FilterOption[] = [
|
'Market Instructions': [
|
||||||
'Amend LiquidityProvision Order',
|
'Amend LiquidityProvision Order',
|
||||||
'Amend Order',
|
'Amend Order',
|
||||||
'Batch Market Instructions',
|
'Batch Market Instructions',
|
||||||
'Cancel LiquidityProvision Order',
|
'Cancel LiquidityProvision Order',
|
||||||
'Cancel Order',
|
'Cancel Order',
|
||||||
'Cancel Transfer Funds',
|
'Liquidity Provision Order',
|
||||||
'Delegate',
|
'Stop Orders Submission',
|
||||||
'Liquidity Provision Order',
|
'Stop Orders Cancellation',
|
||||||
'Proposal',
|
'Submit Order',
|
||||||
'Stop Orders Submission',
|
'Update Margin Mode',
|
||||||
'Stop Orders Cancellation',
|
],
|
||||||
'Submit Oracle Data',
|
'Transfers and Withdrawals': [
|
||||||
'Submit Order',
|
'Transfer Funds',
|
||||||
'Transfer Funds',
|
'Cancel Transfer Funds',
|
||||||
'Undelegate',
|
'Withdraw',
|
||||||
'Vote on Proposal',
|
],
|
||||||
'Withdraw',
|
Governance: [
|
||||||
];
|
'Batch Proposal',
|
||||||
|
'Delegate',
|
||||||
|
'Undelegate',
|
||||||
|
'Vote on Proposal',
|
||||||
|
'Proposal',
|
||||||
|
],
|
||||||
|
Referrals: [
|
||||||
|
'Apply Referral Code',
|
||||||
|
'Create Referral Set',
|
||||||
|
'Join Team',
|
||||||
|
'Update Party Profile',
|
||||||
|
'Update Referral Set',
|
||||||
|
],
|
||||||
|
'External Data': ['Chain Event', 'Submit Oracle Data'],
|
||||||
|
Validators: [
|
||||||
|
'Ethereum Key Rotate Submission',
|
||||||
|
'Issue Signatures',
|
||||||
|
'Key Rotate Submission',
|
||||||
|
'Node Signature',
|
||||||
|
'Node Vote',
|
||||||
|
'Protocol Upgrade',
|
||||||
|
'Register new Node',
|
||||||
|
'State Variable Proposal',
|
||||||
|
'Validator Heartbeat',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
// Alphabetised list of transaction types to nest under a 'More...' submenu
|
export const AllFilterOptions: FilterOption[] =
|
||||||
export const SecondaryFilterOptions: FilterOption[] = [
|
Object.values(filterOptions).flat();
|
||||||
'Chain Event',
|
|
||||||
'Ethereum Key Rotate Submission',
|
|
||||||
'Issue Signatures',
|
|
||||||
'Key Rotate Submission',
|
|
||||||
'Node Signature',
|
|
||||||
'Node Vote',
|
|
||||||
'Protocol Upgrade',
|
|
||||||
'Register new Node',
|
|
||||||
'State Variable Proposal',
|
|
||||||
'Validator Heartbeat',
|
|
||||||
];
|
|
||||||
|
|
||||||
export const AllFilterOptions: FilterOption[] = [
|
|
||||||
...PrimaryFilterOptions,
|
|
||||||
...SecondaryFilterOptions,
|
|
||||||
];
|
|
||||||
|
|
||||||
export interface TxFilterProps {
|
export interface TxFilterProps {
|
||||||
filters: Set<FilterOption>;
|
filters: Set<FilterOption>;
|
||||||
@@ -122,46 +135,33 @@ export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
|
|||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{PrimaryFilterOptions.map((f) => (
|
|
||||||
<DropdownMenuCheckboxItem
|
{Object.entries(filterOptions).map(([key, value]) => (
|
||||||
key={f}
|
<DropdownMenuSub key={key}>
|
||||||
checked={filters.has(f)}
|
<DropdownMenuSubTrigger>
|
||||||
onCheckedChange={() => {
|
{t(key)}
|
||||||
// NOTE: These act like radio buttons until the API supports multiple filters
|
<Icon name="chevron-right" />
|
||||||
setFilters(new Set([f]));
|
</DropdownMenuSubTrigger>
|
||||||
}}
|
<DropdownMenuSubContent>
|
||||||
id={`radio-${f}`}
|
{value.map((f) => (
|
||||||
>
|
<DropdownMenuCheckboxItem
|
||||||
{f}
|
key={f}
|
||||||
<DropdownMenuItemIndicator>
|
checked={filters.has(f)}
|
||||||
<Icon name="tick-circle" />
|
onCheckedChange={(checked) => {
|
||||||
</DropdownMenuItemIndicator>
|
// NOTE: These act like radio buttons until the API supports multiple filters
|
||||||
</DropdownMenuCheckboxItem>
|
setFilters(new Set([f]));
|
||||||
|
}}
|
||||||
|
id={`radio-${f}`}
|
||||||
|
>
|
||||||
|
{f}
|
||||||
|
<DropdownMenuItemIndicator>
|
||||||
|
<Icon name="tick-circle" className="inline" />
|
||||||
|
</DropdownMenuItemIndicator>
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuSubContent>
|
||||||
|
</DropdownMenuSub>
|
||||||
))}
|
))}
|
||||||
<DropdownMenuSub>
|
|
||||||
<DropdownMenuSubTrigger>
|
|
||||||
{t('More Types')}
|
|
||||||
<Icon name="chevron-right" />
|
|
||||||
</DropdownMenuSubTrigger>
|
|
||||||
<DropdownMenuSubContent>
|
|
||||||
{SecondaryFilterOptions.map((f) => (
|
|
||||||
<DropdownMenuCheckboxItem
|
|
||||||
key={f}
|
|
||||||
checked={filters.has(f)}
|
|
||||||
onCheckedChange={(checked) => {
|
|
||||||
// NOTE: These act like radio buttons until the API supports multiple filters
|
|
||||||
setFilters(new Set([f]));
|
|
||||||
}}
|
|
||||||
id={`radio-${f}`}
|
|
||||||
>
|
|
||||||
{f}
|
|
||||||
<DropdownMenuItemIndicator>
|
|
||||||
<Icon name="tick-circle" className="inline" />
|
|
||||||
</DropdownMenuItemIndicator>
|
|
||||||
</DropdownMenuCheckboxItem>
|
|
||||||
))}
|
|
||||||
</DropdownMenuSubContent>
|
|
||||||
</DropdownMenuSub>
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -61,53 +61,4 @@ describe('TxsListNavigation', () => {
|
|||||||
|
|
||||||
expect(nextPageMock).toHaveBeenCalledTimes(1);
|
expect(nextPageMock).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('disables "Older" button if hasMoreTxs is false', () => {
|
|
||||||
render(
|
|
||||||
<TxsListNavigation
|
|
||||||
refreshTxs={NOOP}
|
|
||||||
nextPage={NOOP}
|
|
||||||
previousPage={NOOP}
|
|
||||||
hasMoreTxs={false}
|
|
||||||
hasPreviousPage={false}
|
|
||||||
>
|
|
||||||
<span></span>
|
|
||||||
</TxsListNavigation>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByText('Older')).toBeDisabled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('disables "Newer" button if hasPreviousPage is false', () => {
|
|
||||||
render(
|
|
||||||
<TxsListNavigation
|
|
||||||
refreshTxs={NOOP}
|
|
||||||
nextPage={NOOP}
|
|
||||||
previousPage={NOOP}
|
|
||||||
hasMoreTxs={true}
|
|
||||||
hasPreviousPage={false}
|
|
||||||
>
|
|
||||||
<span></span>
|
|
||||||
</TxsListNavigation>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByText('Newer')).toBeDisabled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('disables both buttons when more and previous are false', () => {
|
|
||||||
render(
|
|
||||||
<TxsListNavigation
|
|
||||||
refreshTxs={NOOP}
|
|
||||||
nextPage={NOOP}
|
|
||||||
previousPage={NOOP}
|
|
||||||
hasMoreTxs={false}
|
|
||||||
hasPreviousPage={false}
|
|
||||||
>
|
|
||||||
<span></span>
|
|
||||||
</TxsListNavigation>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByText('Newer')).toBeDisabled();
|
|
||||||
expect(screen.getByText('Older')).toBeDisabled();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ export interface TxListNavigationProps {
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
hasPreviousPage: boolean;
|
hasPreviousPage: boolean;
|
||||||
hasMoreTxs: boolean;
|
hasMoreTxs: boolean;
|
||||||
children: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
isEmpty?: boolean;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Displays a list of transactions with filters and controls to navigate through the list.
|
* Displays a list of transactions with filters and controls to navigate through the list.
|
||||||
@@ -21,9 +22,8 @@ export const TxsListNavigation = ({
|
|||||||
refreshTxs,
|
refreshTxs,
|
||||||
nextPage,
|
nextPage,
|
||||||
previousPage,
|
previousPage,
|
||||||
hasMoreTxs,
|
|
||||||
hasPreviousPage,
|
|
||||||
children,
|
children,
|
||||||
|
isEmpty,
|
||||||
loading = false,
|
loading = false,
|
||||||
}: TxListNavigationProps) => {
|
}: TxListNavigationProps) => {
|
||||||
return (
|
return (
|
||||||
@@ -35,7 +35,6 @@ export const TxsListNavigation = ({
|
|||||||
<Button
|
<Button
|
||||||
className="mr-2"
|
className="mr-2"
|
||||||
size="xs"
|
size="xs"
|
||||||
disabled={!hasPreviousPage || loading}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
previousPage();
|
previousPage();
|
||||||
}}
|
}}
|
||||||
@@ -44,7 +43,7 @@ export const TxsListNavigation = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="xs"
|
||||||
disabled={!hasMoreTxs}
|
disabled={isEmpty}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
nextPage();
|
nextPage();
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { components } from '../../../types/explorer';
|
import type { components } from '../../../types/explorer';
|
||||||
import { VoteIcon } from '../vote-icon/vote-icon';
|
import { VoteIcon } from '../vote-icon/vote-icon';
|
||||||
|
import { ExternalChainIcon } from '../links/external-explorer-link/external-chain-icon';
|
||||||
|
|
||||||
interface TxOrderTypeProps {
|
interface TxOrderTypeProps {
|
||||||
orderType: string;
|
orderType: string;
|
||||||
@@ -48,6 +49,8 @@ const displayString: StringMap = {
|
|||||||
StopOrdersSubmission: 'Stop',
|
StopOrdersSubmission: 'Stop',
|
||||||
StopOrdersCancellation: 'Cancel stop',
|
StopOrdersCancellation: 'Cancel stop',
|
||||||
'Stop Orders Cancellation': 'Cancel stop',
|
'Stop Orders Cancellation': 'Cancel stop',
|
||||||
|
'Apply Referral Code': 'Referral',
|
||||||
|
'Create Referral Set': 'Create referral',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getLabelForStopOrderType(
|
export function getLabelForStopOrderType(
|
||||||
@@ -80,6 +83,12 @@ export function getLabelForOrderType(
|
|||||||
if (command.orderSubmission.icebergOpts) {
|
if (command.orderSubmission.icebergOpts) {
|
||||||
return 'Iceberg';
|
return 'Iceberg';
|
||||||
}
|
}
|
||||||
|
if (command.orderSubmission.type === 'TYPE_MARKET') {
|
||||||
|
return 'Market order';
|
||||||
|
}
|
||||||
|
if (command.orderSubmission.type === 'TYPE_LIMIT') {
|
||||||
|
return 'Limit order';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 'Order';
|
return 'Order';
|
||||||
}
|
}
|
||||||
@@ -180,6 +189,9 @@ export function getLabelForChainEvent(
|
|||||||
}
|
}
|
||||||
return t('Multisig update');
|
return t('Multisig update');
|
||||||
} else if (chainEvent.contractCall) {
|
} else if (chainEvent.contractCall) {
|
||||||
|
if (chainEvent.contractCall.error) {
|
||||||
|
return t('Call error');
|
||||||
|
}
|
||||||
return t('Contract call');
|
return t('Contract call');
|
||||||
}
|
}
|
||||||
return t('Chain Event');
|
return t('Chain Event');
|
||||||
@@ -249,6 +261,11 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
|||||||
data-testid="tx-type"
|
data-testid="tx-type"
|
||||||
className={`text-sm rounded-md leading-tight px-2 inline-block whitespace-nowrap ${colours}`}
|
className={`text-sm rounded-md leading-tight px-2 inline-block whitespace-nowrap ${colours}`}
|
||||||
>
|
>
|
||||||
|
{command?.chainEvent && (
|
||||||
|
<ExternalChainIcon
|
||||||
|
chainId={command?.chainEvent?.contractCall?.sourceChainId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{type}
|
{type}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ export const ENV = {
|
|||||||
blockExplorerUrl: windowOrDefault('NX_BLOCK_EXPLORER'),
|
blockExplorerUrl: windowOrDefault('NX_BLOCK_EXPLORER'),
|
||||||
tendermintUrl: windowOrDefault('NX_TENDERMINT_URL'),
|
tendermintUrl: windowOrDefault('NX_TENDERMINT_URL'),
|
||||||
tendermintWebsocketUrl: windowOrDefault('NX_TENDERMINT_WEBSOCKET_URL'),
|
tendermintWebsocketUrl: windowOrDefault('NX_TENDERMINT_WEBSOCKET_URL'),
|
||||||
ethExplorerUrl: windowOrDefault('NX_ETHERSCAN_URL'),
|
|
||||||
governanceUrl: windowOrDefault('NX_VEGA_GOVERNANCE_URL'),
|
governanceUrl: windowOrDefault('NX_VEGA_GOVERNANCE_URL'),
|
||||||
vegaRepoUrl: windowOrDefault('NX_VEGA_REPO_URL'),
|
vegaRepoUrl: windowOrDefault('NX_VEGA_REPO_URL'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export const getTxsDataUrl = (params: IGetTxsDataUrl) => {
|
|||||||
url.searchParams.append('first', count);
|
url.searchParams.append('first', count);
|
||||||
url.searchParams.append('after', params.after);
|
url.searchParams.append('after', params.after);
|
||||||
} else {
|
} else {
|
||||||
url.searchParams.append('last', count);
|
url.searchParams.append('first', count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hacky fix for param as array
|
// Hacky fix for param as array
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ describe('getTxsDataUrl', () => {
|
|||||||
count: 10,
|
count: 10,
|
||||||
baseUrl: 'https://example.com/transactions',
|
baseUrl: 'https://example.com/transactions',
|
||||||
};
|
};
|
||||||
const expectedUrl = 'https://example.com/transactions?last=10';
|
const expectedUrl = 'https://example.com/transactions?first=10';
|
||||||
|
|
||||||
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
|
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
|
||||||
});
|
});
|
||||||
@@ -41,7 +41,7 @@ describe('getTxsDataUrl', () => {
|
|||||||
baseUrl: 'https://example.com/transactions',
|
baseUrl: 'https://example.com/transactions',
|
||||||
};
|
};
|
||||||
const expectedUrl =
|
const expectedUrl =
|
||||||
'https://example.com/transactions?last=10&filters[cmd.type]=Made%20Up%20Transaction&filters[tx.submitter]=1234';
|
'https://example.com/transactions?first=10&filters[cmd.type]=Made%20Up%20Transaction&filters[tx.submitter]=1234';
|
||||||
|
|
||||||
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
|
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -31,14 +31,14 @@ export interface IUseTxsData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useTxsData = ({
|
export const useTxsData = ({
|
||||||
count = 25,
|
count = 50,
|
||||||
before,
|
before,
|
||||||
after,
|
after,
|
||||||
filters,
|
filters,
|
||||||
party,
|
party,
|
||||||
}: IUseTxsData) => {
|
}: IUseTxsData) => {
|
||||||
const [, setSearchParams] = useSearchParams();
|
const [, setSearchParams] = useSearchParams();
|
||||||
let hasMoreTxs = true;
|
let hasMoreTxs = false;
|
||||||
let txsData: BlockExplorerTransactionResult[] = [];
|
let txsData: BlockExplorerTransactionResult[] = [];
|
||||||
|
|
||||||
const url = getTxsDataUrl({
|
const url = getTxsDataUrl({
|
||||||
@@ -60,8 +60,8 @@ export const useTxsData = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nextPage = useCallback(() => {
|
const nextPage = useCallback(() => {
|
||||||
const after = data?.transactions.at(-1)?.cursor || '';
|
const before = data?.transactions.at(-1)?.cursor || '';
|
||||||
const params: URLSearchParamsInit = { after };
|
const params: URLSearchParamsInit = { before };
|
||||||
if (filters) {
|
if (filters) {
|
||||||
params.filters = Array.from(filters).join(',');
|
params.filters = Array.from(filters).join(',');
|
||||||
}
|
}
|
||||||
@@ -69,8 +69,8 @@ export const useTxsData = ({
|
|||||||
}, [filters, data, setSearchParams]);
|
}, [filters, data, setSearchParams]);
|
||||||
|
|
||||||
const previousPage = useCallback(() => {
|
const previousPage = useCallback(() => {
|
||||||
const before = data?.transactions[0]?.cursor || '';
|
const after = data?.transactions[0]?.cursor || '';
|
||||||
const params: URLSearchParamsInit = { before };
|
const params: URLSearchParamsInit = { after };
|
||||||
if (filters && filters.size > 0 && filters.size === 1) {
|
if (filters && filters.size > 0 && filters.size === 1) {
|
||||||
params.filters = Array.from(filters)[0];
|
params.filters = Array.from(filters)[0];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const Block = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
{blockData && (
|
{blockData && 'result' in blockData && (
|
||||||
<>
|
<>
|
||||||
<TableWithTbody className="mb-8">
|
<TableWithTbody className="mb-8">
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export const Layout = () => {
|
|||||||
<ProtocolUpgradeInProgressNotification />
|
<ProtocolUpgradeInProgressNotification />
|
||||||
</div>
|
</div>
|
||||||
<div className={fixedWidthClasses}>
|
<div className={fixedWidthClasses}>
|
||||||
<main className="p-4">
|
<main className="md:p-4">
|
||||||
{!isHome && <BreadcrumbsContainer className="mb-4" />}
|
{!isHome && <BreadcrumbsContainer className="mb-4" />}
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ fragment ExplorerOracleDataSource on OracleSpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sourceChainId
|
||||||
filters {
|
filters {
|
||||||
key {
|
key {
|
||||||
name
|
name
|
||||||
@@ -118,6 +119,7 @@ fragment ExplorerOracleDataSource on OracleSpec {
|
|||||||
address
|
address
|
||||||
requiredConfirmations
|
requiredConfirmations
|
||||||
method
|
method
|
||||||
|
sourceChainId
|
||||||
filters {
|
filters {
|
||||||
key {
|
key {
|
||||||
type
|
type
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ fragment ExplorerOracleDataSourceSpec on ExternalDataSourceSpec {
|
|||||||
sourceType {
|
sourceType {
|
||||||
... on EthCallSpec {
|
... on EthCallSpec {
|
||||||
address
|
address
|
||||||
|
sourceChainId
|
||||||
}
|
}
|
||||||
... on DataSourceSpecConfiguration {
|
... on DataSourceSpecConfiguration {
|
||||||
signers {
|
signers {
|
||||||
|
|||||||
@@ -5,19 +5,19 @@ import * as Apollo from '@apollo/client';
|
|||||||
const defaultOptions = {} as const;
|
const defaultOptions = {} as const;
|
||||||
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', 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', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, 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 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, sourceChainId: number, 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', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, 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, 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', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, 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 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, sourceChainId: number, 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', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, 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, 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', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, 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 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, sourceChainId: number, 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', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, 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 ExplorerOracleDataConnectionFragmentDoc = gql`
|
export const ExplorerOracleDataConnectionFragmentDoc = gql`
|
||||||
fragment ExplorerOracleDataConnection on OracleSpec {
|
fragment ExplorerOracleDataConnection on OracleSpec {
|
||||||
@@ -101,6 +101,7 @@ export const ExplorerOracleDataSourceFragmentDoc = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sourceChainId
|
||||||
filters {
|
filters {
|
||||||
key {
|
key {
|
||||||
name
|
name
|
||||||
@@ -141,6 +142,7 @@ export const ExplorerOracleDataSourceFragmentDoc = gql`
|
|||||||
address
|
address
|
||||||
requiredConfirmations
|
requiredConfirmations
|
||||||
method
|
method
|
||||||
|
sourceChainId
|
||||||
filters {
|
filters {
|
||||||
key {
|
key {
|
||||||
type
|
type
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ export type ExplorerOracleFutureFragment = { __typename?: 'Future', dataSourceSp
|
|||||||
|
|
||||||
export type ExplorerOracleForMarketsMarketFragment = { __typename?: 'Market', id: string, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Spot' } } } };
|
export type ExplorerOracleForMarketsMarketFragment = { __typename?: 'Market', id: string, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Spot' } } } };
|
||||||
|
|
||||||
export type ExplorerOracleDataSourceSpecFragment = { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, 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 } | { __typename?: 'EthCallSpec', address: string } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } };
|
export type ExplorerOracleDataSourceSpecFragment = { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, 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 } | { __typename?: 'EthCallSpec', address: string, sourceChainId: number } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } };
|
||||||
|
|
||||||
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, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Spot' } } } } }> } | null, oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, 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 } | { __typename?: 'EthCallSpec', address: string } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
|
export type ExplorerOracleFormMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Spot' } } } } }> } | null, oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, 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 } | { __typename?: 'EthCallSpec', address: string, sourceChainId: number } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
|
||||||
|
|
||||||
export const ExplorerOracleFutureFragmentDoc = gql`
|
export const ExplorerOracleFutureFragmentDoc = gql`
|
||||||
fragment ExplorerOracleFuture on Future {
|
fragment ExplorerOracleFuture on Future {
|
||||||
@@ -90,6 +90,7 @@ export const ExplorerOracleDataSourceSpecFragmentDoc = gql`
|
|||||||
sourceType {
|
sourceType {
|
||||||
... on EthCallSpec {
|
... on EthCallSpec {
|
||||||
address
|
address
|
||||||
|
sourceChainId
|
||||||
}
|
}
|
||||||
... on DataSourceSpecConfiguration {
|
... on DataSourceSpecConfiguration {
|
||||||
signers {
|
signers {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export function isInternalSourceType(s: SourceType) {
|
|||||||
|
|
||||||
export function getExternalType(s: SourceType) {
|
export function getExternalType(s: SourceType) {
|
||||||
if (s.sourceType.__typename === 'EthCallSpec') {
|
if (s.sourceType.__typename === 'EthCallSpec') {
|
||||||
return 'Ethereum Contract Call';
|
return 'Contract Call';
|
||||||
} else {
|
} else {
|
||||||
return 'External Data';
|
return 'External Data';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,24 @@
|
|||||||
import { TableRow, TableCell, TableHeader } from '../../../components/table';
|
import { TableRow, TableCell, TableHeader } from '../../../components/table';
|
||||||
import type { SourceType } from './oracle';
|
import type { SourceType } from './oracle';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../components/links/eth-explorer-link/eth-explorer-link';
|
} from '../../../components/links/external-explorer-link/external-explorer-link';
|
||||||
|
import { getExternalChainLabel } from '../../../components/links/external-explorer-link/external-chain';
|
||||||
|
import { t } from 'i18next';
|
||||||
|
|
||||||
interface OracleDetailsEthSourceProps {
|
interface OracleDetailsEthSourceProps {
|
||||||
sourceType: SourceType;
|
sourceType: SourceType;
|
||||||
|
chain?: string;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Given an Oracle that sources data from Ethereum, this component will render
|
* Given an Oracle that sources data from Ethereum, this component will render
|
||||||
* a link to the smart contract and some basic details
|
* a link to the smart contract and some basic details
|
||||||
*/
|
*/
|
||||||
export function OracleEthSource({ sourceType }: OracleDetailsEthSourceProps) {
|
export function OracleEthSource({
|
||||||
|
sourceType,
|
||||||
|
chain = '1',
|
||||||
|
}: OracleDetailsEthSourceProps) {
|
||||||
if (
|
if (
|
||||||
sourceType.__typename !== 'DataSourceDefinitionExternal' ||
|
sourceType.__typename !== 'DataSourceDefinitionExternal' ||
|
||||||
sourceType.sourceType.__typename !== 'EthCallSpec'
|
sourceType.sourceType.__typename !== 'EthCallSpec'
|
||||||
@@ -26,11 +32,20 @@ export function OracleEthSource({ sourceType }: OracleDetailsEthSourceProps) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const chainLabel = getExternalChainLabel(chain);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableHeader scope="row">Ethereum Contract</TableHeader>
|
<TableHeader scope="row">
|
||||||
|
{chainLabel} {t('Contract')}
|
||||||
|
</TableHeader>
|
||||||
<TableCell modifier="bordered">
|
<TableCell modifier="bordered">
|
||||||
<EthExplorerLink id={address} type={EthExplorerLinkTypes.address} />
|
<ExternalExplorerLink
|
||||||
|
chain={chain}
|
||||||
|
id={address}
|
||||||
|
type={EthExplorerLinkTypes.address}
|
||||||
|
code={true}
|
||||||
|
/>
|
||||||
<span className="mx-3">⇒</span>
|
<span className="mx-3">⇒</span>
|
||||||
<code>{sourceType.sourceType.method}</code>
|
<code>{sourceType.sourceType.method}</code>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { PartyLink } from '../../../components/links';
|
import { PartyLink } from '../../../components/links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../components/links/eth-explorer-link/eth-explorer-link';
|
} from '../../../components/links/external-explorer-link/external-explorer-link';
|
||||||
import { TableRow, TableCell, TableHeader } from '../../../components/table';
|
import { TableRow, TableCell, TableHeader } from '../../../components/table';
|
||||||
import { remove0x } from '@vegaprotocol/utils';
|
import { remove0x } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
@@ -37,13 +37,15 @@ export function getAddressLink(signer: Signer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (signer.__typename === 'ETHAddress') {
|
if (signer.__typename === 'ETHAddress') {
|
||||||
return <EthExplorerLink id={address} type={EthExplorerLinkTypes.address} />;
|
return (
|
||||||
|
<ExternalExplorerLink id={address} type={EthExplorerLinkTypes.address} />
|
||||||
|
);
|
||||||
} else if (signer.__typename === 'PubKey' && address.length !== 64) {
|
} else if (signer.__typename === 'PubKey' && address.length !== 64) {
|
||||||
// This is a hack: some older oracles were submitted before proper checks stopped
|
// This is a hack: some older oracles were submitted before proper checks stopped
|
||||||
// ETH addresses being returned as Vega addresses
|
// ETH addresses being returned as Vega addresses
|
||||||
// Hacky 0x prefixing as a bonus
|
// Hacky 0x prefixing as a bonus
|
||||||
return (
|
return (
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={`0x${remove0x(address)}`}
|
id={`0x${remove0x(address)}`}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
@@ -61,7 +63,10 @@ interface OracleDetailsSignersProps {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an Oracle, this component will render either a link to Ethereum
|
* Given an Oracle, this component will render either a link to Ethereum
|
||||||
* or the Vega party depending on which type is specified
|
* or the Vega party depending on which type is specified.
|
||||||
|
*
|
||||||
|
* Note that this won't be shown for external contract calls as they do not
|
||||||
|
* have a signer in the same way.
|
||||||
*/
|
*/
|
||||||
export function OracleSigners({ sourceType }: OracleDetailsSignersProps) {
|
export function OracleSigners({ sourceType }: OracleDetailsSignersProps) {
|
||||||
if (sourceType.__typename !== 'DataSourceDefinitionExternal') {
|
if (sourceType.__typename !== 'DataSourceDefinitionExternal') {
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ export const OracleDetails = ({
|
|||||||
dataConnection,
|
dataConnection,
|
||||||
}: OracleDetailsProps) => {
|
}: OracleDetailsProps) => {
|
||||||
const sourceType = dataSource.dataSourceSpec.spec.data.sourceType;
|
const sourceType = dataSource.dataSourceSpec.spec.data.sourceType;
|
||||||
|
const chain =
|
||||||
|
dataSource.dataSourceSpec.spec.data.sourceType.sourceType.__typename ===
|
||||||
|
'EthCallSpec'
|
||||||
|
? dataSource.dataSourceSpec.spec.data.sourceType.sourceType.sourceChainId.toString()
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -60,7 +65,7 @@ export const OracleDetails = ({
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<OracleSigners sourceType={sourceType} />
|
<OracleSigners sourceType={sourceType} />
|
||||||
<OracleEthSource sourceType={sourceType} />
|
<OracleEthSource sourceType={sourceType} chain={chain} />
|
||||||
<OracleMarkets id={id} />
|
<OracleMarkets id={id} />
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableHeader scope="row">{t('Filter')}</TableHeader>
|
<TableHeader scope="row">{t('Filter')}</TableHeader>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { t } from '@vegaprotocol/i18n';
|
|||||||
import { Routes } from './route-names';
|
import { Routes } from './route-names';
|
||||||
import { NetworkParameters } from './network-parameters';
|
import { NetworkParameters } from './network-parameters';
|
||||||
import type { Params, RouteObject } from 'react-router-dom';
|
import type { Params, RouteObject } from 'react-router-dom';
|
||||||
import { createBrowserRouter } from 'react-router-dom';
|
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { MarketPage, MarketsPage } from './markets';
|
import { MarketPage, MarketsPage } from './markets';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
@@ -29,7 +28,7 @@ import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
|
|||||||
import { remove0x } from '@vegaprotocol/utils';
|
import { remove0x } from '@vegaprotocol/utils';
|
||||||
import { PartyAccountsByAsset } from './parties/id/accounts';
|
import { PartyAccountsByAsset } from './parties/id/accounts';
|
||||||
import { Disclaimer } from './pages/disclaimer';
|
import { Disclaimer } from './pages/disclaimer';
|
||||||
import { FLAGS } from '@vegaprotocol/environment';
|
import { useFeatureFlags } from '@vegaprotocol/environment';
|
||||||
import RestrictedPage from './restricted';
|
import RestrictedPage from './restricted';
|
||||||
|
|
||||||
export type Navigable = {
|
export type Navigable = {
|
||||||
@@ -60,311 +59,315 @@ type Route = RouteItem & {
|
|||||||
children?: RouteItem[];
|
children?: RouteItem[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const partiesRoutes: Route[] = FLAGS.EXPLORER_PARTIES
|
export const useRouterConfig = () => {
|
||||||
? [
|
const featureFlags = useFeatureFlags((state) => state.flags);
|
||||||
{
|
|
||||||
path: Routes.PARTIES,
|
|
||||||
element: <Party />,
|
|
||||||
handle: {
|
|
||||||
name: t('Parties'),
|
|
||||||
text: t('Parties'),
|
|
||||||
breadcrumb: () => <Link to={Routes.PARTIES}>{t('Parties')}</Link>,
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
index: true,
|
|
||||||
element: <Parties />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ':party',
|
|
||||||
element: <Party />,
|
|
||||||
|
|
||||||
children: [
|
const partiesRoutes: Route[] = featureFlags.EXPLORER_PARTIES
|
||||||
{
|
? [
|
||||||
index: true,
|
{
|
||||||
element: <PartySingle />,
|
path: Routes.PARTIES,
|
||||||
handle: {
|
element: <Party />,
|
||||||
breadcrumb: (params: Params<string>) => (
|
handle: {
|
||||||
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
name: t('Parties'),
|
||||||
{truncateMiddle(params.party as string)}
|
text: t('Parties'),
|
||||||
</Link>
|
breadcrumb: () => <Link to={Routes.PARTIES}>{t('Parties')}</Link>,
|
||||||
),
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <Parties />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':party',
|
||||||
|
element: <Party />,
|
||||||
|
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <PartySingle />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
||||||
|
{truncateMiddle(params.party as string)}
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
path: 'assets',
|
||||||
path: 'assets',
|
element: <Party />,
|
||||||
element: <Party />,
|
handle: {
|
||||||
handle: {
|
breadcrumb: (params: Params<string>) => (
|
||||||
breadcrumb: (params: Params<string>) => (
|
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
||||||
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
{truncateMiddle(params.party as string)}
|
||||||
{truncateMiddle(params.party as string)}
|
</Link>
|
||||||
</Link>
|
),
|
||||||
),
|
},
|
||||||
},
|
children: [
|
||||||
children: [
|
{
|
||||||
{
|
index: true,
|
||||||
index: true,
|
element: <PartyAccountsByAsset />,
|
||||||
element: <PartyAccountsByAsset />,
|
handle: {
|
||||||
handle: {
|
breadcrumb: () => {
|
||||||
breadcrumb: () => {
|
return t('Assets');
|
||||||
return t('Assets');
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
],
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const assetsRoutes: Route[] = featureFlags.EXPLORER_ASSETS
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
path: Routes.ASSETS,
|
||||||
|
handle: {
|
||||||
|
name: t('Assets'),
|
||||||
|
text: t('Assets'),
|
||||||
|
breadcrumb: () => <Link to={Routes.ASSETS}>{t('Assets')}</Link>,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <AssetsPage />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':assetId',
|
||||||
|
element: <AssetPage />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<AssetLink assetId={params.assetId as string} />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
},
|
],
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const assetsRoutes: Route[] = FLAGS.EXPLORER_ASSETS
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
path: Routes.ASSETS,
|
|
||||||
handle: {
|
|
||||||
name: t('Assets'),
|
|
||||||
text: t('Assets'),
|
|
||||||
breadcrumb: () => <Link to={Routes.ASSETS}>{t('Assets')}</Link>,
|
|
||||||
},
|
},
|
||||||
children: [
|
]
|
||||||
{
|
: [];
|
||||||
index: true,
|
|
||||||
element: <AssetsPage />,
|
const genesisRoutes: Route[] = featureFlags.EXPLORER_GENESIS
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
path: Routes.GENESIS,
|
||||||
|
handle: {
|
||||||
|
name: t('Genesis'),
|
||||||
|
text: t('Genesis Parameters'),
|
||||||
|
breadcrumb: () => (
|
||||||
|
<Link to={Routes.GENESIS}>{t('Genesis Parameters')}</Link>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
|
element: <Genesis />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const governanceRoutes: Route[] = featureFlags.EXPLORER_GOVERNANCE
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
path: Routes.GOVERNANCE,
|
||||||
|
handle: {
|
||||||
|
name: t('Governance proposals'),
|
||||||
|
text: t('Governance Proposals'),
|
||||||
|
breadcrumb: () => (
|
||||||
|
<Link to={Routes.GOVERNANCE}>{t('Governance Proposals')}</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
element: <Proposals />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const marketsRoutes: Route[] = featureFlags.EXPLORER_MARKETS
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
path: Routes.MARKETS,
|
||||||
|
handle: {
|
||||||
|
name: t('Markets'),
|
||||||
|
text: t('Markets'),
|
||||||
|
breadcrumb: () => <Link to={Routes.MARKETS}>{t('Markets')}</Link>,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <MarketsPage />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':marketId',
|
||||||
|
element: <MarketPage />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<MarketLink id={params.marketId as string} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const networkParametersRoutes: Route[] =
|
||||||
|
featureFlags.EXPLORER_NETWORK_PARAMETERS
|
||||||
|
? [
|
||||||
{
|
{
|
||||||
path: ':assetId',
|
path: Routes.NETWORK_PARAMETERS,
|
||||||
element: <AssetPage />,
|
|
||||||
handle: {
|
handle: {
|
||||||
breadcrumb: (params: Params<string>) => (
|
name: t('NetworkParameters'),
|
||||||
<AssetLink assetId={params.assetId as string} />
|
text: t('Network Parameters'),
|
||||||
|
breadcrumb: () => (
|
||||||
|
<Link to={Routes.NETWORK_PARAMETERS}>
|
||||||
|
{t('Network Parameters')}
|
||||||
|
</Link>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
element: <NetworkParameters />,
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
},
|
: [];
|
||||||
]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const genesisRoutes: Route[] = FLAGS.EXPLORER_GENESIS
|
const validators: Route[] = featureFlags.EXPLORER_VALIDATORS
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
path: Routes.GENESIS,
|
path: Routes.VALIDATORS,
|
||||||
handle: {
|
handle: {
|
||||||
name: t('Genesis'),
|
name: t('Validators'),
|
||||||
text: t('Genesis Parameters'),
|
text: t('Validators'),
|
||||||
breadcrumb: () => (
|
breadcrumb: () => (
|
||||||
<Link to={Routes.GENESIS}>{t('Genesis Parameters')}</Link>
|
<Link to={Routes.VALIDATORS}>{t('Validators')}</Link>
|
||||||
),
|
),
|
||||||
},
|
|
||||||
element: <Genesis />,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const governanceRoutes: Route[] = FLAGS.EXPLORER_GOVERNANCE
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
path: Routes.GOVERNANCE,
|
|
||||||
handle: {
|
|
||||||
name: t('Governance proposals'),
|
|
||||||
text: t('Governance Proposals'),
|
|
||||||
breadcrumb: () => (
|
|
||||||
<Link to={Routes.GOVERNANCE}>{t('Governance Proposals')}</Link>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
element: <Proposals />,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const marketsRoutes: Route[] = FLAGS.EXPLORER_MARKETS
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
path: Routes.MARKETS,
|
|
||||||
handle: {
|
|
||||||
name: t('Markets'),
|
|
||||||
text: t('Markets'),
|
|
||||||
breadcrumb: () => <Link to={Routes.MARKETS}>{t('Markets')}</Link>,
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
index: true,
|
|
||||||
element: <MarketsPage />,
|
|
||||||
},
|
},
|
||||||
{
|
element: <ValidatorsPage />,
|
||||||
path: ':marketId',
|
},
|
||||||
element: <MarketPage />,
|
]
|
||||||
handle: {
|
: [];
|
||||||
breadcrumb: (params: Params<string>) => (
|
|
||||||
<MarketLink id={params.marketId as string} />
|
const linkTo = (...segments: (string | undefined)[]) =>
|
||||||
),
|
compact(segments).join('/');
|
||||||
|
|
||||||
|
const routerConfig: Route[] = [
|
||||||
|
{
|
||||||
|
path: Routes.HOME,
|
||||||
|
element: <Layout />,
|
||||||
|
handle: {
|
||||||
|
name: t('Home'),
|
||||||
|
text: t('Home'),
|
||||||
|
breadcrumb: () => <Link to={Routes.HOME}>{t('Home')}</Link>,
|
||||||
|
},
|
||||||
|
errorElement: <ErrorBoundary />,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <Home />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: Routes.TX,
|
||||||
|
handle: {
|
||||||
|
name: t('Txs'),
|
||||||
|
text: t('Transactions'),
|
||||||
|
breadcrumb: () => <Link to={Routes.TX}>{t('Transactions')}</Link>,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: ':txHash',
|
||||||
|
element: <Tx />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<Link to={linkTo(Routes.TX, params.txHash)}>
|
||||||
|
{truncateMiddle(remove0x(params.txHash as string))}
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <TxsList />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: Routes.BLOCKS,
|
||||||
|
handle: {
|
||||||
|
name: t('Blocks'),
|
||||||
|
text: t('Blocks'),
|
||||||
|
breadcrumb: () => <Link to={Routes.BLOCKS}>{t('Blocks')}</Link>,
|
||||||
},
|
},
|
||||||
],
|
element: <BlockPage />,
|
||||||
},
|
children: [
|
||||||
]
|
{
|
||||||
: [];
|
index: true,
|
||||||
|
element: <Blocks />,
|
||||||
const networkParametersRoutes: Route[] = FLAGS.EXPLORER_NETWORK_PARAMETERS
|
},
|
||||||
? [
|
{
|
||||||
{
|
path: ':block',
|
||||||
path: Routes.NETWORK_PARAMETERS,
|
element: <Block />,
|
||||||
handle: {
|
handle: {
|
||||||
name: t('NetworkParameters'),
|
breadcrumb: (params: Params<string>) => (
|
||||||
text: t('Network Parameters'),
|
<Link to={linkTo(Routes.BLOCKS, params.block)}>
|
||||||
breadcrumb: () => (
|
{params.block}
|
||||||
<Link to={Routes.NETWORK_PARAMETERS}>
|
</Link>
|
||||||
{t('Network Parameters')}
|
),
|
||||||
</Link>
|
},
|
||||||
),
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
element: <NetworkParameters />,
|
{
|
||||||
},
|
path: Routes.ORACLES,
|
||||||
]
|
handle: {
|
||||||
: [];
|
name: t('Oracles'),
|
||||||
|
text: t('Oracles'),
|
||||||
const validators: Route[] = FLAGS.EXPLORER_VALIDATORS
|
breadcrumb: () => <Link to={Routes.ORACLES}>{t('Oracles')}</Link>,
|
||||||
? [
|
},
|
||||||
{
|
element: <OraclePage />,
|
||||||
path: Routes.VALIDATORS,
|
children: [
|
||||||
handle: {
|
{
|
||||||
name: t('Validators'),
|
index: true,
|
||||||
text: t('Validators'),
|
element: <Oracles />,
|
||||||
breadcrumb: () => (
|
},
|
||||||
<Link to={Routes.VALIDATORS}>{t('Validators')}</Link>
|
{
|
||||||
),
|
path: ':id',
|
||||||
|
element: <Oracle />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<Link to={linkTo(Routes.ORACLES, params.id)}>
|
||||||
|
{truncateMiddle(params.id as string)}
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
element: <ValidatorsPage />,
|
{
|
||||||
},
|
path: Routes.DISCLAIMER,
|
||||||
]
|
element: <Disclaimer />,
|
||||||
: [];
|
handle: {
|
||||||
|
name: t('Disclaimer'),
|
||||||
const linkTo = (...segments: (string | undefined)[]) =>
|
text: t('Disclaimer'),
|
||||||
compact(segments).join('/');
|
breadcrumb: () => (
|
||||||
|
<Link to={Routes.DISCLAIMER}>{t('Disclaimer')}</Link>
|
||||||
export const routerConfig: Route[] = [
|
),
|
||||||
{
|
},
|
||||||
path: Routes.HOME,
|
},
|
||||||
element: <Layout />,
|
...partiesRoutes,
|
||||||
handle: {
|
...assetsRoutes,
|
||||||
name: t('Home'),
|
...genesisRoutes,
|
||||||
text: t('Home'),
|
...governanceRoutes,
|
||||||
breadcrumb: () => <Link to={Routes.HOME}>{t('Home')}</Link>,
|
...marketsRoutes,
|
||||||
|
...networkParametersRoutes,
|
||||||
|
...validators,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
errorElement: <ErrorBoundary />,
|
{
|
||||||
children: [
|
path: Routes.RESTRICTED,
|
||||||
{
|
element: <RestrictedPage />,
|
||||||
index: true,
|
handle: {
|
||||||
element: <Home />,
|
name: t('Restricted'),
|
||||||
|
text: t('Restricted'),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: Routes.TX,
|
|
||||||
handle: {
|
|
||||||
name: t('Txs'),
|
|
||||||
text: t('Transactions'),
|
|
||||||
breadcrumb: () => <Link to={Routes.TX}>{t('Transactions')}</Link>,
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: ':txHash',
|
|
||||||
element: <Tx />,
|
|
||||||
handle: {
|
|
||||||
breadcrumb: (params: Params<string>) => (
|
|
||||||
<Link to={linkTo(Routes.TX, params.txHash)}>
|
|
||||||
{truncateMiddle(remove0x(params.txHash as string))}
|
|
||||||
</Link>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: true,
|
|
||||||
element: <TxsList />,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: Routes.BLOCKS,
|
|
||||||
handle: {
|
|
||||||
name: t('Blocks'),
|
|
||||||
text: t('Blocks'),
|
|
||||||
breadcrumb: () => <Link to={Routes.BLOCKS}>{t('Blocks')}</Link>,
|
|
||||||
},
|
|
||||||
element: <BlockPage />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
index: true,
|
|
||||||
element: <Blocks />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ':block',
|
|
||||||
element: <Block />,
|
|
||||||
handle: {
|
|
||||||
breadcrumb: (params: Params<string>) => (
|
|
||||||
<Link to={linkTo(Routes.BLOCKS, params.block)}>
|
|
||||||
{params.block}
|
|
||||||
</Link>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: Routes.ORACLES,
|
|
||||||
handle: {
|
|
||||||
name: t('Oracles'),
|
|
||||||
text: t('Oracles'),
|
|
||||||
breadcrumb: () => <Link to={Routes.ORACLES}>{t('Oracles')}</Link>,
|
|
||||||
},
|
|
||||||
element: <OraclePage />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
index: true,
|
|
||||||
element: <Oracles />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ':id',
|
|
||||||
element: <Oracle />,
|
|
||||||
handle: {
|
|
||||||
breadcrumb: (params: Params<string>) => (
|
|
||||||
<Link to={linkTo(Routes.ORACLES, params.id)}>
|
|
||||||
{truncateMiddle(params.id as string)}
|
|
||||||
</Link>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: Routes.DISCLAIMER,
|
|
||||||
element: <Disclaimer />,
|
|
||||||
handle: {
|
|
||||||
name: t('Disclaimer'),
|
|
||||||
text: t('Disclaimer'),
|
|
||||||
breadcrumb: () => (
|
|
||||||
<Link to={Routes.DISCLAIMER}>{t('Disclaimer')}</Link>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
...partiesRoutes,
|
|
||||||
...assetsRoutes,
|
|
||||||
...genesisRoutes,
|
|
||||||
...governanceRoutes,
|
|
||||||
...marketsRoutes,
|
|
||||||
...networkParametersRoutes,
|
|
||||||
...validators,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: Routes.RESTRICTED,
|
|
||||||
element: <RestrictedPage />,
|
|
||||||
handle: {
|
|
||||||
name: t('Restricted'),
|
|
||||||
text: t('Restricted'),
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
return routerConfig;
|
||||||
|
};
|
||||||
export const router = createBrowserRouter(routerConfig);
|
|
||||||
|
|||||||
@@ -51,9 +51,10 @@ export const TxsListFiltered = () => {
|
|||||||
refreshTxs={refreshTxs}
|
refreshTxs={refreshTxs}
|
||||||
nextPage={nextPage}
|
nextPage={nextPage}
|
||||||
previousPage={previousPage}
|
previousPage={previousPage}
|
||||||
hasPreviousPage={true}
|
hasPreviousPage={hasMoreTxs}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
hasMoreTxs={hasMoreTxs}
|
hasMoreTxs={hasMoreTxs}
|
||||||
|
isEmpty={txsData.length === 0}
|
||||||
>
|
>
|
||||||
<TxsFilter
|
<TxsFilter
|
||||||
filters={filters}
|
filters={filters}
|
||||||
@@ -70,7 +71,16 @@ export const TxsListFiltered = () => {
|
|||||||
txs={txsData}
|
txs={txsData}
|
||||||
loadMoreTxs={nextPage}
|
loadMoreTxs={nextPage}
|
||||||
error={error}
|
error={error}
|
||||||
className="mb-28 w-full min-w-[400px]"
|
className="mb-4 w-full min-w-[400px]"
|
||||||
|
/>
|
||||||
|
<TxsListNavigation
|
||||||
|
refreshTxs={refreshTxs}
|
||||||
|
nextPage={nextPage}
|
||||||
|
previousPage={previousPage}
|
||||||
|
hasPreviousPage={hasMoreTxs}
|
||||||
|
loading={loading}
|
||||||
|
hasMoreTxs={hasMoreTxs}
|
||||||
|
isEmpty={txsData.length === 0}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ const Tx = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!data || !data?.transaction) {
|
||||||
|
errorMessage = 'Transaction not found';
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
@@ -49,7 +53,7 @@ const Tx = () => {
|
|||||||
<TxDetails
|
<TxDetails
|
||||||
className="mb-28"
|
className="mb-28"
|
||||||
txData={data?.transaction}
|
txData={data?.transaction}
|
||||||
pubKey={data?.transaction.submitter}
|
pubKey={data?.transaction?.submitter}
|
||||||
/>
|
/>
|
||||||
</RenderFetched>
|
</RenderFetched>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ interface TxDetailsProps {
|
|||||||
export const txDetailsTruncateLength = 30;
|
export const txDetailsTruncateLength = 30;
|
||||||
|
|
||||||
export const TxDetails = ({ txData, pubKey }: TxDetailsProps) => {
|
export const TxDetails = ({ txData, pubKey }: TxDetailsProps) => {
|
||||||
if (!txData) {
|
if (!txData || !pubKey) {
|
||||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
return <>{t('Transaction could not be found')}</>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<section className="mb-10" key={txData.hash}>
|
<section className="mb-10" key={txData.hash}>
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns:xodm="http://www.corel.com/coreldraw/odm/2003" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 2500 2500" style="enable-background:new 0 0 2500 2500;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:none;}
|
||||||
|
.st1{fill:#213147;}
|
||||||
|
.st2{fill:#12AAFF;}
|
||||||
|
.st3{fill:#9DCCED;}
|
||||||
|
.st4{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g id="Layer_x0020_1">
|
||||||
|
<g id="_2405588477232">
|
||||||
|
<rect class="st0" width="2500" height="2500"></rect>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M226,760v980c0,63,33,120,88,152l849,490c54,31,121,31,175,0l849-490c54-31,88-89,88-152V760 c0-63-33-120-88-152l-849-490c-54-31-121-31-175,0L314,608c-54,31-87,89-87,152H226z"></path>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st2" d="M1435,1440l-121,332c-3,9-3,19,0,29l208,571l241-139l-289-793C1467,1422,1442,1422,1435,1440z"></path>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st2" d="M1678,882c-7-18-32-18-39,0l-121,332c-3,9-3,19,0,29l341,935l241-139L1678,883V882z"></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st3" d="M1250,155c6,0,12,2,17,5l918,530c11,6,17,18,17,30v1060c0,12-7,24-17,30l-918,530c-5,3-11,5-17,5 s-12-2-17-5l-918-530c-11-6-17-18-17-30V719c0-12,7-24,17-30l918-530c5-3,11-5,17-5l0,0V155z M1250,0c-33,0-65,8-95,25L237,555 c-59,34-95,96-95,164v1060c0,68,36,130,95,164l918,530c29,17,62,25,95,25s65-8,95-25l918-530c59-34,95-96,95-164V719 c0-68-36-130-95-164L1344,25c-29-17-62-25-95-25l0,0H1250z"></path>
|
||||||
|
</g>
|
||||||
|
<polygon class="st1" points="642,2179 727,1947 897,2088 738,2234 "></polygon>
|
||||||
|
<g>
|
||||||
|
<path class="st4" d="M1172,644H939c-17,0-33,11-39,27L401,2039l241,139l550-1507c5-14-5-28-19-28L1172,644z"></path>
|
||||||
|
<path class="st4" d="M1580,644h-233c-17,0-33,11-39,27L738,2233l241,139l620-1701c5-14-5-28-19-28V644z"></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><g fill="none" fill-rule="evenodd"><circle cx="16" cy="16" r="16" fill="#136485"/><path fill="#FFF" d="M10.436 31.006a16.008 16.008 0 0 1-5.604-3.548l.147-.257c2.388-3.773 4.533-7.678 6.148-11.85 1.713-4.425 3.084-8.967 4.39-13.527.117-.407.256-.807.384-1.21.138.158.188.305.23.454.82 2.926 1.613 5.86 2.464 8.776 1.55 5.313 3.73 10.353 6.617 15.077.337.55.91 1.472 1.72 2.762a15.988 15.988 0 0 1-6.035 3.554 4320.193 4320.193 0 0 0-5.002-15.17l-.154-.002c-1.166 3.277-2.934 8.257-5.305 14.941zM16.075.049h-.124L16 0l.075.049z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 622 B |
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Creator: CorelDRAW 2019 (64-Bit) -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="100%" height="100%" version="1.1" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
viewBox="0 0 784.37 1277.39"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:xodm="http://www.corel.com/coreldraw/odm/2003">
|
||||||
|
<g id="Layer_x0020_1">
|
||||||
|
<metadata id="CorelCorpID_0Corel-Layer"/>
|
||||||
|
<g id="_1421394342400">
|
||||||
|
<g>
|
||||||
|
<polygon fill="#343434" fill-rule="nonzero" points="392.07,0 383.5,29.11 383.5,873.74 392.07,882.29 784.13,650.54 "/>
|
||||||
|
<polygon fill="#8C8C8C" fill-rule="nonzero" points="392.07,0 -0,650.54 392.07,882.29 392.07,472.33 "/>
|
||||||
|
<polygon fill="#3C3C3B" fill-rule="nonzero" points="392.07,956.52 387.24,962.41 387.24,1263.28 392.07,1277.38 784.37,724.89 "/>
|
||||||
|
<polygon fill="#8C8C8C" fill-rule="nonzero" points="392.07,1277.38 392.07,956.52 -0,724.89 "/>
|
||||||
|
<polygon fill="#141414" fill-rule="nonzero" points="392.07,882.29 784.13,650.54 392.07,472.33 "/>
|
||||||
|
<polygon fill="#393939" fill-rule="nonzero" points="0,650.54 392.07,882.29 392.07,472.33 "/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 428 428" style="enable-background:new 0 0 428 428;" xml:space="preserve">
|
||||||
|
<path style="fill:#00193C;" d="M125.8,243.7c12.3,0,24.3-4.1,34-11.6l-78-78c-18.8,24.3-14.3,59.3,10,78.1
|
||||||
|
C101.6,239.6,113.5,243.7,125.8,243.7L125.8,243.7z"/>
|
||||||
|
<path style="fill:#00193C;" d="M357.8,188c0-12.3-4.1-24.3-11.6-34l-78,78c24.3,18.8,59.2,14.3,78-10
|
||||||
|
C353.7,212.3,357.8,200.3,357.8,188z"/>
|
||||||
|
<path style="fill:#00193C;" d="M397.1,103.1l-34.5,34.5c27.8,33.3,23.4,82.9-9.9,110.7c-29.2,24.4-71.6,24.4-100.8,0L214,286.2
|
||||||
|
l-37.8-37.8c-33.3,27.8-82.9,23.4-110.7-9.9c-24.4-29.2-24.4-71.6,0-100.8L47.8,120L31,103.1C10.7,136.5,0,174.9,0,214
|
||||||
|
c0,118.2,95.8,214,214,214s214-95.8,214-214C428.1,174.9,417.3,136.5,397.1,103.1z"/>
|
||||||
|
<path style="fill:#00193C;" d="M368.8,66.3c-81.5-85.5-216.9-88.7-302.4-7.2c-2.5,2.4-4.9,4.8-7.2,7.2c-5.3,5.6-10.3,11.4-15,17.5
|
||||||
|
L214,253.7L383.8,83.8C379.2,77.7,374.1,71.9,368.8,66.3z M214,28c50,0,96.6,19.3,131.6,54.5L214,214.1L82.4,82.5
|
||||||
|
C117.4,47.3,164,28,214,28z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"short_name": "Mainnet Stats",
|
"short_name": "Explorer VEGA",
|
||||||
"name": "Vega Mainnet statistics",
|
"name": "Vega Protocol - Explorer",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "favicon.ico",
|
"src": "favicon.ico",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user