Compare commits
49
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3835bd67f | ||
|
|
4688d9b839 | ||
|
|
92a291522b | ||
|
|
f62ceb1c64 | ||
|
|
d504065385 | ||
|
|
41b9ce87d8 | ||
|
|
f2c1904e93 | ||
|
|
f86b0706fe | ||
|
|
9d8e37192f | ||
|
|
8bb52ff0cf | ||
|
|
0131612414 | ||
|
|
a6672d213f | ||
|
|
62f368da10 | ||
|
|
f3e2fe746d | ||
|
|
8b19572dc9 | ||
|
|
80399d04f7 | ||
|
|
8322fc7edd | ||
|
|
46752816ec | ||
|
|
f99f78780c | ||
|
|
f7037bca80 | ||
|
|
ba39720f05 | ||
|
|
6d35f2b39d | ||
|
|
78afecc2e5 | ||
|
|
3de5b07495 | ||
|
|
e944d3e37c | ||
|
|
5596392835 | ||
|
|
5c57106c04 | ||
|
|
2fc688f477 | ||
|
|
9ea8c839db | ||
|
|
d7e2da7a54 | ||
|
|
b29c268257 | ||
|
|
01ca05a313 | ||
|
|
e3c6dd41c9 | ||
|
|
fbd01dc1bd | ||
|
|
af6719cc9d | ||
|
|
c433a4ee06 | ||
|
|
e3a00ada05 | ||
|
|
aa38e0c001 | ||
|
|
86da521da5 | ||
|
|
c6df34fe95 | ||
|
|
c7d0803164 | ||
|
|
250a654544 | ||
|
|
7f5e8ebb15 | ||
|
|
ccbe34e172 | ||
|
|
27e8ce88bf | ||
|
|
41804d9869 | ||
|
|
293288286b | ||
|
|
a77765b1e9 | ||
|
|
2453d7841a |
@@ -1,6 +1,6 @@
|
|||||||
# Related issues 🔗
|
# Related issues 🔗
|
||||||
|
|
||||||
Issue: #[Issue number here]
|
Closes #[Issue number here]
|
||||||
|
|
||||||
# Description ℹ️
|
# Description ℹ️
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
name: (CI) Console tests
|
name: (CI) Console tests
|
||||||
|
|
||||||
|
env:
|
||||||
|
VEGA_VERSION: v0.72.14
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
@@ -11,7 +14,7 @@ jobs:
|
|||||||
run-tests:
|
run-tests:
|
||||||
name: run-tests
|
name: run-tests
|
||||||
runs-on: console-test
|
runs-on: console-test
|
||||||
timeout-minutes: 20
|
timeout-minutes: 40
|
||||||
steps:
|
steps:
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# check-out frontend-monorepo
|
# check-out frontend-monorepo
|
||||||
@@ -67,23 +70,39 @@ jobs:
|
|||||||
repository: vegaprotocol/console-test
|
repository: vegaprotocol/console-test
|
||||||
path: './console-test'
|
path: './console-test'
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# install dependencies if cache does not exist
|
# install dependencies
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
working-directory: ./console-test
|
working-directory: ./console-test
|
||||||
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
|
|
||||||
run: poetry install --no-interaction --no-root
|
run: poetry install --no-interaction --no-root
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# install vega binaries
|
# find vega binaries path
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Find vega binaries path
|
||||||
|
id: vega_bin_path
|
||||||
|
working-directory: ./console-test
|
||||||
|
run: echo path=$(poetry run python -c "import vega_sim; print(vega_sim.vega_bin_path)") >> $GITHUB_OUTPUT
|
||||||
|
#----------------------------------------------
|
||||||
|
# vega binaries cache
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Vega binaries cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
id: vega_binaries_cache
|
||||||
|
with:
|
||||||
|
path: ${{ steps.vega_bin_path.outputs.path }}
|
||||||
|
key: ${{ runner.os }}-vega-binaries-${{ env.VEGA_VERSION }}
|
||||||
|
#----------------------------------------------
|
||||||
|
# install vega binaries
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Install vega binaries
|
- name: Install vega binaries
|
||||||
working-directory: ./console-test
|
working-directory: ./console-test
|
||||||
run: poetry run python -m vega_sim.tools.load_binaries --force
|
if: steps.vega_binaries_cache.outputs.cache-hit != 'true'
|
||||||
|
run: poetry run python -m vega_sim.tools.load_binaries --force --version $VEGA_VERSION
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# install playwright
|
# install playwright
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: install playwright
|
- name: install playwright
|
||||||
run: poetry run playwright install
|
run: poetry run playwright install --with-deps chromium
|
||||||
working-directory: ./console-test
|
working-directory: ./console-test
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# run tests
|
# run tests
|
||||||
|
|||||||
@@ -155,10 +155,10 @@ jobs:
|
|||||||
- name: Sanity check docker image
|
- name: Sanity check docker image
|
||||||
run: |
|
run: |
|
||||||
echo "Check ipfs-hash"
|
echo "Check ipfs-hash"
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash
|
docker run --rm --entrypoint /bin/sh ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local -c 'cat /ipfs-hash'
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash > ${{ matrix.app }}-ipfs-hash
|
docker run --rm --entrypoint /bin/sh ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local -c 'cat /ipfs-hash' > ${{ matrix.app }}-ipfs-hash
|
||||||
echo "List html directory"
|
echo "List html directory"
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree /usr/share/nginx/html'
|
docker run --rm --entrypoint /bin/sh ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local -c 'apk add --update tree; tree /usr/share/nginx/html'
|
||||||
|
|
||||||
- name: Publish dist as docker image (ghcr)
|
- name: Publish dist as docker image (ghcr)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
|
|||||||
@@ -113,6 +113,20 @@ In order to run a container on port 3000:
|
|||||||
docker run -p 3000:80 [TAG]
|
docker run -p 3000:80 [TAG]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
On top of that there are two possible scenarios for running docker image - using nginx server (default) of ipfs daemon.
|
||||||
|
|
||||||
|
to run ipfs on port 3000:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -p 3000:80 [TAG] ipfs
|
||||||
|
```
|
||||||
|
|
||||||
|
to run nginx on port 3000:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -p 3000:80 [TAG]
|
||||||
|
```
|
||||||
|
|
||||||
## Build instructions
|
## Build instructions
|
||||||
|
|
||||||
The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of Console either for the web, or ready for pinning on IPFS.
|
The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of Console either for the web, or ready for pinning on IPFS.
|
||||||
@@ -150,7 +164,7 @@ As a prerequisite you need to perform build of `dist` directory and move its con
|
|||||||
You can build any of the containers locally with the following command:
|
You can build any of the containers locally with the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build --dockerfile docker/node-outside-docker.Dockerfile . --tag=[TAG]
|
docker build -f docker/node-outside-docker.Dockerfile . --tag=[TAG]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Verifying ipfs-hash of existing current application version
|
### Verifying ipfs-hash of existing current application version
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket
|
|||||||
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
||||||
NX_VEGA_ENV=DEVNET
|
NX_VEGA_ENV=DEVNET
|
||||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocke
|
|||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
NX_VEGA_ENV=MAINNET
|
NX_VEGA_ENV=MAINNET
|
||||||
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
|
|||||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||||
NX_VEGA_ENV=TESTNET
|
NX_VEGA_ENV=TESTNET
|
||||||
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ NX_VEGA_ENV=CUSTOM
|
|||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_TXS_LIST=0
|
NX_EXPLORER_TXS_LIST=0
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
|||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
||||||
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://be.vega.community
|
NX_TENDERMINT_URL=https://be.vega.community
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
||||||
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
# .env is stagnet1, so there are no overrides required
|
# .env is stagnet1, so there are no overrides required
|
||||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}'
|
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}'
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||||
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
|||||||
NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks
|
NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
||||||
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/
|
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ NX_BLOCK_EXPLORER=
|
|||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
const { params } = useNetworkParams([
|
const { params } = useNetworkParams([
|
||||||
NetworkParams.governance_proposal_market_requiredMajority,
|
NetworkParams.governance_proposal_market_requiredMajority,
|
||||||
]);
|
]);
|
||||||
const tokenLink = useLinks(DApp.Token);
|
const tokenLink = useLinks(DApp.Governance);
|
||||||
const requiredMajorityPercentage = useMemo(() => {
|
const requiredMajorityPercentage = useMemo(() => {
|
||||||
const requiredMajority =
|
const requiredMajority =
|
||||||
params?.governance_proposal_market_requiredMajority ?? 1;
|
params?.governance_proposal_market_requiredMajority ?? 1;
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ export const BundleSigners = ({
|
|||||||
tx,
|
tx,
|
||||||
id,
|
id,
|
||||||
}: BundleSignersProps) => {
|
}: BundleSignersProps) => {
|
||||||
const tokenLink = useLinks(DApp.Token);
|
const tokenLink = useLinks(DApp.Governance);
|
||||||
|
|
||||||
const bridgeFunction: BridgeFunction =
|
const bridgeFunction: BridgeFunction =
|
||||||
tx?.changes?.erc20 && 'contractAddress' in tx.changes.erc20
|
tx?.changes?.erc20 && 'contractAddress' in tx.changes.erc20
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ export const ValidatorsPage = () => {
|
|||||||
const [vegaDialog, setVegaDialog] = useState<boolean>(false);
|
const [vegaDialog, setVegaDialog] = useState<boolean>(false);
|
||||||
const [tmDialog, setTmDialog] = useState<boolean>(false);
|
const [tmDialog, setTmDialog] = useState<boolean>(false);
|
||||||
|
|
||||||
const tokenLink = useLinks(DApp.Token);
|
const tokenLink = useLinks(DApp.Governance);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
|
|||||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
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_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ NX_VEGA_ENV=DEVNET
|
|||||||
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
||||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ NX_VEGA_ENV=MAINNET
|
|||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://etherscan.io
|
NX_ETHERSCAN_URL=https://etherscan.io
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ 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_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|||||||
@@ -19,7 +19,22 @@ export const upgradeProposalsData = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: {
|
node: {
|
||||||
upgradeBlockHeight: '1955065',
|
upgradeBlockHeight: '10001',
|
||||||
|
vegaReleaseTag: 'v0.71.0+dev-12156-bca1d57e',
|
||||||
|
approvers: [
|
||||||
|
'02a6531716b7a6d82779b7793c3ad2fcb47290ea2ff0912c56f61219bd9675ff',
|
||||||
|
'121934387281812a2d5e6913e5d57c0f85a8f169e2752347ee2e23b52d46623c',
|
||||||
|
'65c80e2f5f84e2109eec30810f137ba04cbbecaba8f27706c146cc6c6f90db29',
|
||||||
|
'bd6339d2428c79ac3bc9011771236d17bac92bcb1806423388d52fb440043aef',
|
||||||
|
],
|
||||||
|
status: 'PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED',
|
||||||
|
__typename: 'ProtocolUpgradeProposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProtocolUpgradeProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
upgradeBlockHeight: '20',
|
||||||
vegaReleaseTag: 'v0.71.0+dev-12156-bca1d57e',
|
vegaReleaseTag: 'v0.71.0+dev-12156-bca1d57e',
|
||||||
approvers: [
|
approvers: [
|
||||||
'02a6531716b7a6d82779b7793c3ad2fcb47290ea2ff0912c56f61219bd9675ff',
|
'02a6531716b7a6d82779b7793c3ad2fcb47290ea2ff0912c56f61219bd9675ff',
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ context(
|
|||||||
closeStakingDialog();
|
closeStakingDialog();
|
||||||
navigateTo(navigation.validators);
|
navigateTo(navigation.validators);
|
||||||
cy.get(`[row-id="${0}"]`)
|
cy.get(`[row-id="${0}"]`)
|
||||||
.eq(1)
|
.first()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId(stakeValidatorListTotalStake)
|
cy.getByTestId(stakeValidatorListTotalStake)
|
||||||
.should('have.text', '3,002.00')
|
.should('have.text', '3,002.00')
|
||||||
@@ -222,7 +222,7 @@ context(
|
|||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
cy.get(`[row-id="${1}"]`)
|
cy.get(`[row-id="${1}"]`)
|
||||||
.eq(1)
|
.first()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId(stakeValidatorListTotalStake)
|
cy.getByTestId(stakeValidatorListTotalStake)
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
@@ -262,10 +262,10 @@ context(
|
|||||||
'2'
|
'2'
|
||||||
);
|
);
|
||||||
waitForBeginningOfEpoch();
|
waitForBeginningOfEpoch();
|
||||||
cy.getByTestId(stakeValidatorListStakePercentage).should(
|
cy.getByTestId(
|
||||||
'have.text',
|
stakeValidatorListStakePercentage,
|
||||||
'50.02%'
|
epochTimeout
|
||||||
);
|
).should('have.text', '50.02%');
|
||||||
navigateTo(navigation.validators);
|
navigateTo(navigation.validators);
|
||||||
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%');
|
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const proposalDocumentationLink = 'proposal-documentation-link';
|
|||||||
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
|
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
|
||||||
const governanceDocsUrl = 'https://vega.xyz/governance';
|
const governanceDocsUrl = 'https://vega.xyz/governance';
|
||||||
const networkUpgradeProposalListItem = 'protocol-upgrade-proposals-list-item';
|
const networkUpgradeProposalListItem = 'protocol-upgrade-proposals-list-item';
|
||||||
|
const proposalUpgradeBlockHeight = 'protocol-upgrade-proposal-block-height';
|
||||||
const closedProposals = 'closed-proposals';
|
const closedProposals = 'closed-proposals';
|
||||||
const closedProposalToggle = 'closed-proposals-toggle-networkUpgrades';
|
const closedProposalToggle = 'closed-proposals-toggle-networkUpgrades';
|
||||||
const protocolUpgradeTime = 'protocol-upgrade-time';
|
const protocolUpgradeTime = 'protocol-upgrade-time';
|
||||||
@@ -184,7 +185,7 @@ context(
|
|||||||
'have.text',
|
'have.text',
|
||||||
'Vega release tag: v1'
|
'Vega release tag: v1'
|
||||||
);
|
);
|
||||||
cy.getByTestId('protocol-upgrade-proposal-block-height').should(
|
cy.getByTestId(proposalUpgradeBlockHeight).should(
|
||||||
'have.text',
|
'have.text',
|
||||||
'Upgrade block height: 2015942'
|
'Upgrade block height: 2015942'
|
||||||
);
|
);
|
||||||
@@ -199,7 +200,15 @@ context(
|
|||||||
});
|
});
|
||||||
cy.getByTestId(closedProposalToggle).click();
|
cy.getByTestId(closedProposalToggle).click();
|
||||||
cy.getByTestId(closedProposals).within(() => {
|
cy.getByTestId(closedProposals).within(() => {
|
||||||
cy.getByTestId(networkUpgradeProposalListItem).should('have.length', 1);
|
cy.getByTestId(networkUpgradeProposalListItem).should('have.length', 2);
|
||||||
|
cy.getByTestId(networkUpgradeProposalListItem)
|
||||||
|
.first()
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId(proposalUpgradeBlockHeight).should(
|
||||||
|
'contain.text',
|
||||||
|
'10001'
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -170,21 +170,20 @@ export function clickOnValidatorFromList(
|
|||||||
validatorName = null
|
validatorName = null
|
||||||
) {
|
) {
|
||||||
cy.contains('Loading...', epochTimeout).should('not.exist');
|
cy.contains('Loading...', epochTimeout).should('not.exist');
|
||||||
waitForBeginningOfEpoch();
|
|
||||||
// below is to ensure validator list is shown
|
// below is to ensure validator list is shown
|
||||||
cy.get(stakeValidatorListName, { timeout: 10000 }).should('exist');
|
cy.get(stakeValidatorListName, { timeout: 10000 }).should('exist');
|
||||||
cy.get(stakeValidatorListPendingStake, txTimeout).should(
|
cy.get(stakeValidatorListPendingStake, txTimeout).should(
|
||||||
'not.contain',
|
'not.contain',
|
||||||
'2,000,000,000,000,000,000.00' // number due to bug #936
|
'2,000,000,000,000,000,000.00' // number due to bug #936
|
||||||
);
|
);
|
||||||
|
waitForBeginningOfEpoch();
|
||||||
if (validatorName) {
|
if (validatorName) {
|
||||||
cy.contains(validatorName).click();
|
cy.contains(validatorName).click();
|
||||||
} else {
|
} else {
|
||||||
cy.get(`[row-id="${validatorNumber}"]`)
|
cy.get(`[row-id="${validatorNumber}"]`)
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.first()
|
.first()
|
||||||
.as('validatorOnList');
|
.click();
|
||||||
cy.get('@validatorOnList').click();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +195,7 @@ export function validateValidatorListTotalStakeAndShare(
|
|||||||
cy.contains('Loading...', epochTimeout).should('not.exist');
|
cy.contains('Loading...', epochTimeout).should('not.exist');
|
||||||
waitForBeginningOfEpoch();
|
waitForBeginningOfEpoch();
|
||||||
cy.get(`[row-id="${positionOnList}"]`)
|
cy.get(`[row-id="${positionOnList}"]`)
|
||||||
.eq(1)
|
.first()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
|
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
|
||||||
'have.text',
|
'have.text',
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ NX_VEGA_REST_URL=http://localhost:3008/api/v2/
|
|||||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||||
|
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
NX_TENDERMINT_URL=http://localhost:26617
|
NX_TENDERMINT_URL=http://localhost:26617
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fa
|
|||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
|
|||||||
NX_VEGA_REST_URL=https://api.vega.community/api/v2/
|
NX_VEGA_REST_URL=https://api.vega.community/api/v2/
|
||||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet
|
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://be.vega.community
|
NX_TENDERMINT_URL=https://be.vega.community
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
|
|||||||
NX_VEGA_REST_URL=https://api.mainnet-mirror.vega.rocks/api/v2/
|
NX_VEGA_REST_URL=https://api.mainnet-mirror.vega.rocks/api/v2/
|
||||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet
|
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ NX_DELEGATIONS_PAGINATION=50
|
|||||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
|
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/
|
NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/
|
||||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_REST_URL=https://api-validators-testnet.vega.rocks/api/v2/
|
NX_VEGA_REST_URL=https://api-validators-testnet.vega.rocks/api/v2/
|
||||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const HomeProposals = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="mb-16" data-testid="home-proposals">
|
<section className="mb-16 break-all" data-testid="home-proposals">
|
||||||
<Heading title={t('vegaGovernance')} />
|
<Heading title={t('vegaGovernance')} />
|
||||||
<h3 className="mb-6">{t('homeProposalsIntro')}</h3>
|
<h3 className="mb-6">{t('homeProposalsIntro')}</h3>
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ export const Proposal = ({
|
|||||||
voteState={voteState}
|
voteState={voteState}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="my-10">
|
<div className="my-10 break-all">
|
||||||
<ProposalChangeTable proposal={proposal} />
|
<ProposalChangeTable proposal={proposal} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
-2
@@ -352,7 +352,6 @@ export const ConsensusValidatorsTable = ({
|
|||||||
field: ValidatorFields.RANKING_INDEX,
|
field: ValidatorFields.RANKING_INDEX,
|
||||||
headerName: '#',
|
headerName: '#',
|
||||||
width: 60,
|
width: 60,
|
||||||
pinned: 'left',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: ValidatorFields.VALIDATOR,
|
field: ValidatorFields.VALIDATOR,
|
||||||
@@ -362,7 +361,6 @@ export const ConsensusValidatorsTable = ({
|
|||||||
if (a === b) return 0;
|
if (a === b) return 0;
|
||||||
return a > b ? 1 : -1;
|
return a > b ? 1 : -1;
|
||||||
},
|
},
|
||||||
pinned: 'left',
|
|
||||||
width: 260,
|
width: 260,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
-2
@@ -195,14 +195,12 @@ export const StandbyPendingValidatorsTable = ({
|
|||||||
field: ValidatorFields.RANKING_INDEX,
|
field: ValidatorFields.RANKING_INDEX,
|
||||||
headerName: '#',
|
headerName: '#',
|
||||||
width: 60,
|
width: 60,
|
||||||
pinned: 'left',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: ValidatorFields.VALIDATOR,
|
field: ValidatorFields.VALIDATOR,
|
||||||
headerName: t(ValidatorFields.VALIDATOR).toString(),
|
headerName: t(ValidatorFields.VALIDATOR).toString(),
|
||||||
cellRenderer: ValidatorRenderer,
|
cellRenderer: ValidatorRenderer,
|
||||||
comparator: ({ name: a }, { name: b }) => Math.sign(a - b),
|
comparator: ({ name: a }, { name: b }) => Math.sign(a - b),
|
||||||
pinned: 'left',
|
|
||||||
width: 260,
|
width: 260,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -122,38 +122,43 @@ export const ValidatorTable = ({
|
|||||||
|
|
||||||
<div className="my-12" data-testid="validator-table">
|
<div className="my-12" data-testid="validator-table">
|
||||||
<SubHeading title={t('profile')} />
|
<SubHeading title={t('profile')} />
|
||||||
<RoundedWrapper paddingBottom={true}>
|
<div className="break-all">
|
||||||
<KeyValueTable data-testid="validator-table-profile">
|
<RoundedWrapper paddingBottom={true}>
|
||||||
<KeyValueTableRow>
|
<KeyValueTable data-testid="validator-table-profile">
|
||||||
<span>{t('id')}</span>
|
<KeyValueTableRow>
|
||||||
<ValidatorTableCell dataTestId="validator-id">
|
<span>{t('id')}</span>
|
||||||
{node.id}
|
<ValidatorTableCell dataTestId="validator-id">
|
||||||
</ValidatorTableCell>
|
{node.id}
|
||||||
</KeyValueTableRow>
|
</ValidatorTableCell>
|
||||||
<KeyValueTableRow>
|
</KeyValueTableRow>
|
||||||
<span>{t('ABOUT THIS VALIDATOR')}</span>
|
<KeyValueTableRow>
|
||||||
|
<span>{t('ABOUT THIS VALIDATOR')}</span>
|
||||||
|
|
||||||
<Tooltip description={t('AboutThisValidatorDescription')}>
|
<Tooltip description={t('AboutThisValidatorDescription')}>
|
||||||
<a data-testid="validator-description-url" href={node.infoUrl}>
|
<a
|
||||||
{node.infoUrl}
|
data-testid="validator-description-url"
|
||||||
</a>
|
href={node.infoUrl}
|
||||||
</Tooltip>
|
>
|
||||||
</KeyValueTableRow>
|
{node.infoUrl}
|
||||||
<KeyValueTableRow noBorder={true}>
|
</a>
|
||||||
<span>
|
</Tooltip>
|
||||||
<strong>{t('STATUS')}</strong>
|
</KeyValueTableRow>
|
||||||
</span>
|
<KeyValueTableRow noBorder={true}>
|
||||||
|
<span>
|
||||||
<Tooltip description={t('ValidatorStatusDescription')}>
|
<strong>{t('STATUS')}</strong>
|
||||||
<span data-testid="validator-status">
|
|
||||||
<strong>
|
|
||||||
{t(statusTranslationKey(node.rankingScore.status))}
|
|
||||||
</strong>
|
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
|
||||||
</KeyValueTableRow>
|
<Tooltip description={t('ValidatorStatusDescription')}>
|
||||||
</KeyValueTable>
|
<span data-testid="validator-status">
|
||||||
</RoundedWrapper>
|
<strong>
|
||||||
|
{t(statusTranslationKey(node.rankingScore.status))}
|
||||||
|
</strong>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</KeyValueTableRow>
|
||||||
|
</KeyValueTable>
|
||||||
|
</RoundedWrapper>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="mb-10">
|
<div className="mb-10">
|
||||||
{t('validatorTableIntro')}{' '}
|
{t('validatorTableIntro')}{' '}
|
||||||
@@ -167,144 +172,154 @@ export const ValidatorTable = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SubHeading title={t('ADDRESS')} />
|
<SubHeading title={t('ADDRESS')} />
|
||||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
<div className="break-all">
|
||||||
<KeyValueTable data-testid="validator-table-address">
|
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||||
<KeyValueTableRow>
|
<KeyValueTable data-testid="validator-table-address">
|
||||||
<span>{t('VEGA ADDRESS / PUBLIC KEY')}</span>
|
<KeyValueTableRow>
|
||||||
<ValidatorTableCell dataTestId="validator-public-key">
|
<span>{t('VEGA ADDRESS / PUBLIC KEY')}</span>
|
||||||
{node.pubkey}
|
<ValidatorTableCell dataTestId="validator-public-key">
|
||||||
</ValidatorTableCell>
|
{node.pubkey}
|
||||||
</KeyValueTableRow>
|
</ValidatorTableCell>
|
||||||
<KeyValueTableRow>
|
</KeyValueTableRow>
|
||||||
<span>{t('SERVER LOCATION')}</span>
|
<KeyValueTableRow>
|
||||||
<ValidatorTableCell dataTestId="validator-server-location">
|
<span>{t('SERVER LOCATION')}</span>
|
||||||
{countryData.find((c) => c.code === node.location)?.name ||
|
<ValidatorTableCell dataTestId="validator-server-location">
|
||||||
t('not available')}
|
{countryData.find((c) => c.code === node.location)?.name ||
|
||||||
</ValidatorTableCell>
|
t('not available')}
|
||||||
</KeyValueTableRow>
|
</ValidatorTableCell>
|
||||||
<KeyValueTableRow noBorder={true}>
|
</KeyValueTableRow>
|
||||||
<span>{t('ETHEREUM ADDRESS')}</span>
|
<KeyValueTableRow noBorder={true}>
|
||||||
<span data-testid="validator-eth-address">
|
<span>{t('ETHEREUM ADDRESS')}</span>
|
||||||
<Link
|
<span data-testid="validator-eth-address">
|
||||||
title={t('View on Etherscan (opens in a new tab)')}
|
<Link
|
||||||
href={`${ETHERSCAN_URL}/address/${node.ethereumAddress}`}
|
title={t('View on Etherscan (opens in a new tab)')}
|
||||||
target="_blank"
|
href={`${ETHERSCAN_URL}/address/${node.ethereumAddress}`}
|
||||||
>
|
target="_blank"
|
||||||
{node.ethereumAddress}
|
>
|
||||||
</Link>
|
{node.ethereumAddress}
|
||||||
</span>
|
</Link>
|
||||||
</KeyValueTableRow>
|
</span>
|
||||||
</KeyValueTable>
|
</KeyValueTableRow>
|
||||||
</RoundedWrapper>
|
</KeyValueTable>
|
||||||
|
</RoundedWrapper>
|
||||||
|
</div>
|
||||||
|
|
||||||
<SubHeading title={t('STAKE')} />
|
<SubHeading title={t('STAKE')} />
|
||||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
<div className="break-all">
|
||||||
<KeyValueTable data-testid="validator-table-stake">
|
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||||
<KeyValueTableRow>
|
<KeyValueTable data-testid="validator-table-stake">
|
||||||
<span>{t('STAKED BY OPERATOR')}</span>
|
<KeyValueTableRow>
|
||||||
|
<span>{t('STAKED BY OPERATOR')}</span>
|
||||||
|
|
||||||
<Tooltip description={t('StakedByOperatorDescription')}>
|
<Tooltip description={t('StakedByOperatorDescription')}>
|
||||||
<span data-testid="staked-by-operator">
|
<span data-testid="staked-by-operator">
|
||||||
{formatNumber(toBigNum(node.stakedByOperator, decimals))}
|
{formatNumber(toBigNum(node.stakedByOperator, decimals))}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</KeyValueTableRow>
|
||||||
|
<KeyValueTableRow>
|
||||||
|
<span>{t('STAKED BY DELEGATES')}</span>
|
||||||
|
|
||||||
|
<Tooltip description={t('StakedByDelegatesDescription')}>
|
||||||
|
<span data-testid="staked-by-delegates">
|
||||||
|
{formatNumber(toBigNum(node.stakedByDelegates, decimals))}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</KeyValueTableRow>
|
||||||
|
<KeyValueTableRow>
|
||||||
|
<span>
|
||||||
|
<strong>{t('TOTAL STAKE')}</strong>
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
|
||||||
</KeyValueTableRow>
|
|
||||||
<KeyValueTableRow>
|
|
||||||
<span>{t('STAKED BY DELEGATES')}</span>
|
|
||||||
|
|
||||||
<Tooltip description={t('StakedByDelegatesDescription')}>
|
<span data-testid="total-stake">
|
||||||
<span data-testid="staked-by-delegates">
|
<strong>
|
||||||
{formatNumber(toBigNum(node.stakedByDelegates, decimals))}
|
{formatNumber(toBigNum(node.stakedTotal, decimals))}
|
||||||
|
</strong>
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</KeyValueTableRow>
|
||||||
</KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
<KeyValueTableRow>
|
<span>{t('PENDING STAKE')}</span>
|
||||||
<span>
|
|
||||||
<strong>{t('TOTAL STAKE')}</strong>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span data-testid="total-stake">
|
<Tooltip description={t('PendingStakeDescription')}>
|
||||||
<strong>
|
<span data-testid="pending-stake">
|
||||||
{formatNumber(toBigNum(node.stakedTotal, decimals))}
|
{formatNumber(toBigNum(node.pendingStake, decimals))}
|
||||||
</strong>
|
</span>
|
||||||
</span>
|
</Tooltip>
|
||||||
</KeyValueTableRow>
|
</KeyValueTableRow>
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow noBorder={true}>
|
||||||
<span>{t('PENDING STAKE')}</span>
|
<span>{t('STAKE SHARE')}</span>
|
||||||
|
|
||||||
<Tooltip description={t('PendingStakeDescription')}>
|
<Tooltip description={t('StakeShareDescription')}>
|
||||||
<span data-testid="pending-stake">
|
<span data-testid="stake-percentage">{stakePercentage}</span>
|
||||||
{formatNumber(toBigNum(node.pendingStake, decimals))}
|
</Tooltip>
|
||||||
</span>
|
</KeyValueTableRow>
|
||||||
</Tooltip>
|
</KeyValueTable>
|
||||||
</KeyValueTableRow>
|
</RoundedWrapper>
|
||||||
<KeyValueTableRow noBorder={true}>
|
</div>
|
||||||
<span>{t('STAKE SHARE')}</span>
|
|
||||||
|
|
||||||
<Tooltip description={t('StakeShareDescription')}>
|
|
||||||
<span data-testid="stake-percentage">{stakePercentage}</span>
|
|
||||||
</Tooltip>
|
|
||||||
</KeyValueTableRow>
|
|
||||||
</KeyValueTable>
|
|
||||||
</RoundedWrapper>
|
|
||||||
|
|
||||||
<SubHeading title={t('PENALTIES')} />
|
<SubHeading title={t('PENALTIES')} />
|
||||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
<div className="break-all">
|
||||||
<KeyValueTable data-testid="validator-table-penalties">
|
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||||
<KeyValueTableRow>
|
<KeyValueTable data-testid="validator-table-penalties">
|
||||||
<span>{t('OVERSTAKED PENALTY')}</span>
|
<KeyValueTableRow>
|
||||||
|
<span>{t('OVERSTAKED PENALTY')}</span>
|
||||||
|
|
||||||
<Tooltip description={t('OverstakedPenaltyDescription')}>
|
<Tooltip description={t('OverstakedPenaltyDescription')}>
|
||||||
<span data-testid="overstaking-penalty">
|
<span data-testid="overstaking-penalty">
|
||||||
{formatNumberPercentage(penalties.overstaked, 2)}
|
{formatNumberPercentage(penalties.overstaked, 2)}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</KeyValueTableRow>
|
</KeyValueTableRow>
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
<span>{t('PERFORMANCE PENALTY')}</span>
|
<span>{t('PERFORMANCE PENALTY')}</span>
|
||||||
|
|
||||||
<Tooltip description={t('PerformancePenaltyDescription')}>
|
<Tooltip description={t('PerformancePenaltyDescription')}>
|
||||||
<span data-testid="performance-penalty">
|
<span data-testid="performance-penalty">
|
||||||
{formatNumberPercentage(penalties.performance, 2)}
|
{formatNumberPercentage(penalties.performance, 2)}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</KeyValueTableRow>
|
||||||
|
<KeyValueTableRow noBorder={true}>
|
||||||
|
<span>
|
||||||
|
<strong>{t('TOTAL PENALTIES')}</strong>
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
<span data-testid="total-penalties">
|
||||||
</KeyValueTableRow>
|
<strong>
|
||||||
<KeyValueTableRow noBorder={true}>
|
{formatNumberPercentage(penalties.overall, 2)}
|
||||||
<span>
|
</strong>
|
||||||
<strong>{t('TOTAL PENALTIES')}</strong>
|
</span>
|
||||||
</span>
|
</KeyValueTableRow>
|
||||||
<span data-testid="total-penalties">
|
</KeyValueTable>
|
||||||
<strong>{formatNumberPercentage(penalties.overall, 2)}</strong>
|
</RoundedWrapper>
|
||||||
</span>
|
</div>
|
||||||
</KeyValueTableRow>
|
|
||||||
</KeyValueTable>
|
|
||||||
</RoundedWrapper>
|
|
||||||
|
|
||||||
<SubHeading title={t('VOTING POWER')} />
|
<SubHeading title={t('VOTING POWER')} />
|
||||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
<div className="break-all">
|
||||||
<KeyValueTable data-testid="validator-table-voting-power">
|
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||||
<KeyValueTableRow>
|
<KeyValueTable data-testid="validator-table-voting-power">
|
||||||
<span>{t('UNNORMALISED VOTING POWER')}</span>
|
<KeyValueTableRow>
|
||||||
|
<span>{t('UNNORMALISED VOTING POWER')}</span>
|
||||||
|
|
||||||
<Tooltip description={t('UnnormalisedVotingPowerDescription')}>
|
<Tooltip description={t('UnnormalisedVotingPowerDescription')}>
|
||||||
<span data-testid="unnormalised-voting-power">
|
<span data-testid="unnormalised-voting-power">
|
||||||
{getUnnormalisedVotingPower(rawValidatorScore)}
|
{getUnnormalisedVotingPower(rawValidatorScore)}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</KeyValueTableRow>
|
||||||
|
<KeyValueTableRow noBorder={true}>
|
||||||
|
<span>
|
||||||
|
<strong>{t('NORMALISED VOTING POWER')}</strong>
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
|
||||||
</KeyValueTableRow>
|
|
||||||
<KeyValueTableRow noBorder={true}>
|
|
||||||
<span>
|
|
||||||
<strong>{t('NORMALISED VOTING POWER')}</strong>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<Tooltip description={t('NormalisedVotingPowerDescription')}>
|
<Tooltip description={t('NormalisedVotingPowerDescription')}>
|
||||||
<strong data-testid="normalised-voting-power">
|
<strong data-testid="normalised-voting-power">
|
||||||
{getNormalisedVotingPower(node.rankingScore.votingPower)}
|
{getNormalisedVotingPower(node.rankingScore.votingPower)}
|
||||||
</strong>
|
</strong>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</KeyValueTableRow>
|
</KeyValueTableRow>
|
||||||
</KeyValueTable>
|
</KeyValueTable>
|
||||||
</RoundedWrapper>
|
</RoundedWrapper>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const TokenDetails = ({
|
|||||||
config.token_vesting_contract?.address || ENV.addresses.tokenVestingAddress;
|
config.token_vesting_contract?.address || ENV.addresses.tokenVestingAddress;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="token-details">
|
<div className="token-details break-all">
|
||||||
<RoundedWrapper>
|
<RoundedWrapper>
|
||||||
<KeyValueTable>
|
<KeyValueTable>
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
|
|||||||
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
|
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
|
||||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||||
NX_SENTRY_DSN=https://dummy@o999999.ingest.sentry.io/9999999
|
NX_SENTRY_DSN=https://dummy@o999999.ingest.sentry.io/9999999
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
|
||||||
# Expose some env vars to cypress environment for market setup
|
# Expose some env vars to cypress environment for market setup
|
||||||
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ NX_VEGA_URL=http://localhost:3008/graphql
|
|||||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||||
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
|
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
|
||||||
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
|
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
|
||||||
# Expose some env vars to cypress environment for market setup
|
# Expose some env vars to cypress environment for market setup
|
||||||
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ describe('deposit actions', { tags: '@smoke' }, () => {
|
|||||||
cy.visit('/#/markets/market-1');
|
cy.visit('/#/markets/market-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Deposit to trade is visible', () => {
|
it.skip('Deposit to trade is visible', () => {
|
||||||
cy.getByTestId('Collateral').click();
|
cy.getByTestId('Collateral').click();
|
||||||
cy.get('[row-id="asset-id"]').contains('tEURO').should('be.visible');
|
cy.get('[row-id="asset-id"]').contains('tEURO').should('be.visible');
|
||||||
cy.contains('[data-testid="deposit"]', 'Deposit').should('be.visible');
|
cy.contains('[data-testid="deposit"]', 'Deposit').should('be.visible');
|
||||||
|
|||||||
@@ -1,256 +0,0 @@
|
|||||||
import { MarketTradingModeMapping } from '@vegaprotocol/types';
|
|
||||||
import { MarketState } from '@vegaprotocol/types';
|
|
||||||
import compact from 'lodash/compact';
|
|
||||||
|
|
||||||
const accordionContent = 'accordion-content';
|
|
||||||
const blockExplorerLink = 'block-explorer-link';
|
|
||||||
const dialogClose = 'dialog-close';
|
|
||||||
const dialogContent = 'dialog-content';
|
|
||||||
const externalLink = 'external-link';
|
|
||||||
const githubLink = 'github-link';
|
|
||||||
const liquidityLink = 'view-liquidity-link';
|
|
||||||
const marketInfoBtn = 'Info';
|
|
||||||
const marketTitle = 'accordion-title';
|
|
||||||
const providerName = 'provider-name';
|
|
||||||
const row = 'key-value-table-row';
|
|
||||||
const verifiedProofs = 'verified-proofs';
|
|
||||||
|
|
||||||
describe('market info is displayed', { tags: '@smoke' }, () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.mockTradingPage();
|
|
||||||
});
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
cy.setOnBoardingViewed();
|
|
||||||
cy.mockTradingPage(MarketState.STATE_ACTIVE);
|
|
||||||
cy.mockSubscription();
|
|
||||||
cy.visit('/#/markets/market-0');
|
|
||||||
cy.wait('@Markets');
|
|
||||||
cy.getByTestId(marketInfoBtn).click();
|
|
||||||
cy.wait('@MarketInfo');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('current fees displayed', () => {
|
|
||||||
// 6002-MDET-101
|
|
||||||
cy.getByTestId(marketTitle).contains('Current fees').click();
|
|
||||||
validateMarketDataRow(0, 'Maker Fee', '0.02%');
|
|
||||||
validateMarketDataRow(1, 'Infrastructure Fee', '0.05%');
|
|
||||||
validateMarketDataRow(2, 'Liquidity Fee', '1.00%');
|
|
||||||
validateMarketDataRow(3, 'Total Fees', '1.07%');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('market price', () => {
|
|
||||||
// 6002-MDET-102
|
|
||||||
cy.getByTestId(marketTitle).contains('Market price').click();
|
|
||||||
validateMarketDataRow(0, 'Mark Price', '46,126.90058');
|
|
||||||
validateMarketDataRow(1, 'Best Bid Price', '44,126.90058 ');
|
|
||||||
validateMarketDataRow(2, 'Best Offer Price', '48,126.90058 ');
|
|
||||||
validateMarketDataRow(3, 'Quote Unit', 'BTC');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('market volume displayed', () => {
|
|
||||||
// 6002-MDET-103
|
|
||||||
cy.getByTestId(marketTitle).contains('Market volume').click();
|
|
||||||
validateMarketDataRow(1, 'Open Interest', '-');
|
|
||||||
validateMarketDataRow(2, 'Best Bid Volume', '1');
|
|
||||||
validateMarketDataRow(3, 'Best Offer Volume', '3');
|
|
||||||
validateMarketDataRow(4, 'Best Static Bid Volume', '2');
|
|
||||||
validateMarketDataRow(5, 'Best Static Offer Volume', '4');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('insurance pool displayed', () => {
|
|
||||||
// 6002-MDET-104
|
|
||||||
cy.getByTestId(marketTitle).contains('Insurance pool').click();
|
|
||||||
validateMarketDataRow(0, 'Balance', '0');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('key details displayed', () => {
|
|
||||||
// 6002-MDET-201
|
|
||||||
cy.getByTestId(marketTitle).contains('Key details').click();
|
|
||||||
|
|
||||||
const rows: [string, string][] = compact([
|
|
||||||
['Name', 'BTCUSD Monthly (30 Jun 2022)'],
|
|
||||||
['Market ID', 'market-0'],
|
|
||||||
Cypress.env('NX_SUCCESSOR_MARKETS') && ['Parent Market ID', 'PARENT-A'],
|
|
||||||
Cypress.env('NX_SUCCESSOR_MARKETS') && [
|
|
||||||
'Insurance Pool Fraction',
|
|
||||||
'0.75',
|
|
||||||
],
|
|
||||||
['Trading Mode', MarketTradingModeMapping.TRADING_MODE_CONTINUOUS],
|
|
||||||
['Market Decimal Places', '5'],
|
|
||||||
['Position Decimal Places', '0'],
|
|
||||||
['Settlement Asset Decimal Places', '5'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
for (const rowNumber in rows) {
|
|
||||||
const [name, value] = rows[rowNumber];
|
|
||||||
validateMarketDataRow(Number(rowNumber), name, value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('instrument displayed', () => {
|
|
||||||
// 6002-MDET-202
|
|
||||||
cy.getByTestId(marketTitle).contains('Instrument').click();
|
|
||||||
|
|
||||||
validateMarketDataRow(0, 'Market Name', 'BTCUSD Monthly (30 Jun 2022)');
|
|
||||||
validateMarketDataRow(1, 'Code', 'BTCUSD.MF21');
|
|
||||||
validateMarketDataRow(2, 'Product Type', 'Future');
|
|
||||||
validateMarketDataRow(3, 'Quote Name', 'BTC');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('oracle displayed', () => {
|
|
||||||
// 6002-MDET-203
|
|
||||||
cy.getByTestId(marketTitle).contains('Oracle').click();
|
|
||||||
|
|
||||||
cy.getByTestId(accordionContent)
|
|
||||||
.getByTestId(providerName)
|
|
||||||
.and('contain', 'Another oracle');
|
|
||||||
|
|
||||||
cy.getByTestId(providerName).should('be.visible').click();
|
|
||||||
cy.getByTestId(dialogContent)
|
|
||||||
.eq(1)
|
|
||||||
.within(() => {
|
|
||||||
cy.getByTestId(blockExplorerLink).contains('Block explorer');
|
|
||||||
cy.getByTestId(githubLink).contains('Oracle repository');
|
|
||||||
});
|
|
||||||
cy.getByTestId(dialogClose).click();
|
|
||||||
|
|
||||||
cy.getByTestId(accordionContent)
|
|
||||||
.getByTestId(verifiedProofs)
|
|
||||||
.and('contain', '1');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('settlement asset displayed', () => {
|
|
||||||
// 6002-MDET-206
|
|
||||||
cy.getByTestId(marketTitle).contains('Settlement asset').click();
|
|
||||||
cy.window().then((win) => {
|
|
||||||
cy.stub(win, 'prompt').returns('DISABLED WINDOW PROMPT');
|
|
||||||
});
|
|
||||||
validateMarketDataRow(0, 'ID', 'asset-id');
|
|
||||||
validateMarketDataRow(1, 'Type', 'ERC20');
|
|
||||||
validateMarketDataRow(2, 'Name', 'Euro');
|
|
||||||
validateMarketDataRow(3, 'Symbol', 'tEURO');
|
|
||||||
validateMarketDataRow(4, 'Decimals', '5');
|
|
||||||
validateMarketDataRow(5, 'Quantum', '1');
|
|
||||||
validateMarketDataRow(6, 'Status', 'Enabled');
|
|
||||||
validateMarketDataRow(7, 'Contract address', '0x0158…78a4');
|
|
||||||
validateMarketDataRow(8, 'Withdrawal threshold', '0.0005');
|
|
||||||
validateMarketDataRow(9, 'Lifetime limit', '1,230');
|
|
||||||
validateMarketDataRow(10, 'Infrastructure fee account balance', '0.00001');
|
|
||||||
validateMarketDataRow(11, 'Global reward pool account balance', '0.00002');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('metadata displayed', () => {
|
|
||||||
// 6002-MDET-207
|
|
||||||
cy.getByTestId(marketTitle).contains('Metadata').click();
|
|
||||||
|
|
||||||
validateMarketDataRow(0, 'Formerly', '076BB86A5AA41E3E');
|
|
||||||
validateMarketDataRow(1, 'Base', 'BTC');
|
|
||||||
validateMarketDataRow(2, 'Quote', 'USD');
|
|
||||||
validateMarketDataRow(3, 'Class', 'fx/crypto');
|
|
||||||
validateMarketDataRow(4, 'Sector', 'crypto');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('risk model displayed', () => {
|
|
||||||
// 6002-MDET-208
|
|
||||||
cy.getByTestId(marketTitle).contains('Risk model').click();
|
|
||||||
validateMarketDataRow(0, 'Tau', '0.0001140771161');
|
|
||||||
validateMarketDataRow(1, 'Risk Aversion Parameter', '0.01');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('risk parameters displayed', () => {
|
|
||||||
// 6002-MDET-209
|
|
||||||
cy.getByTestId(marketTitle).contains('Risk parameters').click();
|
|
||||||
validateMarketDataRow(0, 'R', '0.016');
|
|
||||||
validateMarketDataRow(1, 'Sigma', '0.3');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('risk factors displayed', () => {
|
|
||||||
// 6002-MDET-210
|
|
||||||
cy.getByTestId(marketTitle).contains('Risk factors').click();
|
|
||||||
|
|
||||||
validateMarketDataRow(0, 'Short', '0.008571790367285281');
|
|
||||||
validateMarketDataRow(1, 'Long', '0.008508132993273576');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('price monitoring bounds displayed', () => {
|
|
||||||
// 6002-MDET-211
|
|
||||||
cy.getByTestId(marketTitle).contains('Price monitoring bounds 1').click();
|
|
||||||
cy.get('p.col-span-1').contains('99.99999% probability price bounds');
|
|
||||||
cy.get('p.col-span-1').contains('Within 43,200 seconds');
|
|
||||||
validateMarketDataRow(0, 'Highest Price', '7.97323 ');
|
|
||||||
validateMarketDataRow(1, 'Lowest Price', '6.54701 ');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('liquidity monitoring parameters displayed', () => {
|
|
||||||
// 6002-MDET-212
|
|
||||||
cy.getByTestId(marketTitle)
|
|
||||||
.contains('Liquidity monitoring parameters')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
validateMarketDataRow(0, 'Triggering Ratio', '0.7');
|
|
||||||
validateMarketDataRow(1, 'Time Window', '3,600');
|
|
||||||
validateMarketDataRow(2, 'Scaling Factor', '10');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('liquidity displayed', () => {
|
|
||||||
// 6002-MDET-213
|
|
||||||
cy.getByTestId(marketTitle)
|
|
||||||
.contains(/Liquidity(?! m)/)
|
|
||||||
.click();
|
|
||||||
|
|
||||||
validateMarketDataRow(0, 'Target Stake', '10.00 tBTC');
|
|
||||||
validateMarketDataRow(1, 'Supplied Stake', '0.01 tBTC');
|
|
||||||
validateMarketDataRow(2, 'Market Value Proxy', '20.00 tBTC');
|
|
||||||
cy.getByTestId(liquidityLink).should(
|
|
||||||
'have.text',
|
|
||||||
'View liquidity provision table'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('liquidity price range displayed', () => {
|
|
||||||
// 6002-MDET-214
|
|
||||||
cy.getByTestId(marketTitle).contains('Liquidity price range').click();
|
|
||||||
|
|
||||||
validateMarketDataRow(0, 'Liquidity Price Range', '2.00% of mid price');
|
|
||||||
validateMarketDataRow(1, 'Lowest Price', '45,204.362 BTC');
|
|
||||||
validateMarketDataRow(2, 'Highest Price', '47,049.438 BTC');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('proposal displayed', () => {
|
|
||||||
// 6002-MDET-301
|
|
||||||
cy.getByTestId(marketTitle).contains('Proposal').click();
|
|
||||||
|
|
||||||
cy.getByTestId(accordionContent)
|
|
||||||
.find(`[data-testid="${externalLink}"]`)
|
|
||||||
.first()
|
|
||||||
.should('have.text', 'View governance proposal')
|
|
||||||
.and('have.attr', 'href')
|
|
||||||
.and('contain', '/proposals/market-0');
|
|
||||||
cy.getByTestId(accordionContent)
|
|
||||||
.find(`[data-testid="${externalLink}"]`)
|
|
||||||
.eq(1)
|
|
||||||
.should('have.text', 'Propose a change to market')
|
|
||||||
.and('have.attr', 'href')
|
|
||||||
.and('contain', '/proposals/propose/update-market');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach('close toggle', () => {
|
|
||||||
cy.get('[data-state="open"]').then((tab) => {
|
|
||||||
if (tab) tab.find('button').trigger('click');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function validateMarketDataRow(
|
|
||||||
rowNumber: number,
|
|
||||||
name: string,
|
|
||||||
value: string
|
|
||||||
) {
|
|
||||||
cy.getByTestId(row)
|
|
||||||
.eq(rowNumber)
|
|
||||||
.within(() => {
|
|
||||||
cy.get('dt').should('contain.text', name);
|
|
||||||
cy.get('dd').should('contain.text', value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -24,9 +24,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.getByTestId('deal-ticket-fee-margin-required').within(() => {
|
cy.getByTestId('deal-ticket-fee-margin-required').click();
|
||||||
cy.get('button').click();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('limit order', () => {
|
describe('limit order', () => {
|
||||||
@@ -111,6 +109,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
|||||||
'Total margin available100.01 tDAI'
|
'Total margin available100.01 tDAI'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
cy.getByTestId('deal-ticket-fee-margin-required').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('must have current margin allocation', () => {
|
it('must have current margin allocation', () => {
|
||||||
@@ -120,6 +119,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
|||||||
'Current margin allocation'
|
'Current margin allocation'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
cy.getByTestId('deal-ticket-fee-margin-required').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should open usage breakdown dialog when clicked on current margin allocation', () => {
|
it('should open usage breakdown dialog when clicked on current margin allocation', () => {
|
||||||
@@ -128,6 +128,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
|||||||
});
|
});
|
||||||
cy.getByTestId('usage-breakdown').should('exist');
|
cy.getByTestId('usage-breakdown').should('exist');
|
||||||
cy.getByTestId('dialog-close').click();
|
cy.getByTestId('dialog-close').click();
|
||||||
|
cy.getByTestId('deal-ticket-fee-margin-required').click();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ describe('trades', { tags: '@smoke' }, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('copy price to deal ticket form', () => {
|
it('copy price to deal ticket form', () => {
|
||||||
cy.getByTestId('Order').click();
|
|
||||||
// 6005-THIS-007
|
// 6005-THIS-007
|
||||||
|
cy.getByTestId('order-type-Limit').click();
|
||||||
cy.get(colIdPrice).last().should('be.visible').click();
|
cy.get(colIdPrice).last().should('be.visible').click();
|
||||||
cy.getByTestId('order-price').should('have.value', '171.16898');
|
cy.getByTestId('order-price').should('have.value', '171.16898');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ const dialogContent = 'dialog-content';
|
|||||||
describe('connect vega wallet', { tags: '@smoke', testIsolation: true }, () => {
|
describe('connect vega wallet', { tags: '@smoke', testIsolation: true }, () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Using portfolio page as it requires vega wallet connection
|
// Using portfolio page as it requires vega wallet connection
|
||||||
cy.visit('/#/portfolio');
|
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
cy.setOnBoardingViewed();
|
cy.setOnBoardingViewed();
|
||||||
|
cy.visit('/#/portfolio');
|
||||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+13
-11
@@ -1,27 +1,29 @@
|
|||||||
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
NX_SENTRY_DSN=https://2ffce43721964aafa78277c50654ece4@o286262.ingest.sentry.io/6300613
|
||||||
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/fairground/vegawallet-fairground.toml
|
||||||
NX_VEGA_ENV=STAGNET1
|
NX_VEGA_ENV=TESTNET
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
|
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||||
NX_VEGA_NETWORKS={\"MAINNET\":\"https://console.vega.xyz\",\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\"}
|
NX_VEGA_NETWORKS={\"MAINNET\":\"https://console.vega.xyz\",\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\"}
|
||||||
NX_VEGA_TOKEN_URL=https://governance.fairground.wtf
|
NX_VEGA_TOKEN_URL=https://governance.fairground.wtf
|
||||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||||
|
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
# NX_ICEBERG_ORDERS
|
NX_ICEBERG_ORDERS=true
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
NX_METAMASK_SNAPS=true
|
NX_METAMASK_SNAPS=false
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||||
|
|||||||
@@ -15,15 +15,18 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
|||||||
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-mainnet/codfcglpplgmmlokgilfkpcjnmkbfiel
|
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-mainnet/codfcglpplgmmlokgilfkpcjnmkbfiel
|
||||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet
|
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
|
||||||
# TAG name of the current app version - TODO: bump to the latest upon release
|
# TAG name of the current app version - TODO: bump to the latest upon release
|
||||||
NX_APP_VERSION=v0.21.0-core-0.72.14
|
NX_APP_VERSION=v0.21.2-core-0.72.14
|
||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
NX_METAMASK_SNAPS=false
|
NX_METAMASK_SNAPS=true
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://be.vega.community
|
NX_TENDERMINT_URL=https://be.vega.community
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
|
|||||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
|
|||||||
@@ -16,13 +16,14 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
|||||||
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
NX_METAMASK_SNAPS=false
|
NX_METAMASK_SNAPS=true
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks
|
|||||||
|
|
||||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||||
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
|
|||||||
@@ -1,18 +1,58 @@
|
|||||||
import { DepositContainer } from '@vegaprotocol/deposits';
|
import { DepositContainer } from '@vegaprotocol/deposits';
|
||||||
import { GetStarted } from '../../components/welcome-dialog';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { Intent, TradingAnchorButton } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { GetStartedCheckList } from '../../components/welcome-dialog';
|
||||||
|
import {
|
||||||
|
useGetOnboardingStep,
|
||||||
|
useOnboardingStore,
|
||||||
|
OnboardingStep,
|
||||||
|
} from '../../components/welcome-dialog/use-get-onboarding-step';
|
||||||
|
import { Links, Routes } from '../../pages/client-router';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
export const Deposit = () => {
|
export const Deposit = () => {
|
||||||
return (
|
return (
|
||||||
<div className="py-16 px-8 flex w-full justify-center">
|
<div className="max-w-[600px] px-4 py-8 mx-auto lg:px-8">
|
||||||
<div className="lg:min-w-[700px] min-w-[300px] max-w-[700px]">
|
<h1 className="mb-6 text-4xl uppercase xl:text-5xl font-alpha calt">
|
||||||
<h1 className="text-4xl xl:text-5xl uppercase font-alpha calt">
|
{t('Deposit')}
|
||||||
{t('Deposit')}
|
</h1>
|
||||||
</h1>
|
<div className="flex flex-col gap-6">
|
||||||
<div className="mt-10">
|
<DepositContainer />
|
||||||
<DepositContainer />
|
<DepositGetStarted />
|
||||||
<GetStarted />
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const DepositGetStarted = () => {
|
||||||
|
const onboardingDismissed = useOnboardingStore((store) => store.dismissed);
|
||||||
|
const dismiss = useOnboardingStore((store) => store.dismiss);
|
||||||
|
const step = useGetOnboardingStep();
|
||||||
|
const wrapperClasses = classNames(
|
||||||
|
'flex flex-col py-4 px-6 gap-4 rounded',
|
||||||
|
'bg-vega-blue-300 dark:bg-vega-blue-700',
|
||||||
|
'border border-vega-blue-350 dark:border-vega-blue-650'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dont show unless still onboarding
|
||||||
|
if (onboardingDismissed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="pt-6 border-t border-default">
|
||||||
|
<div className={wrapperClasses}>
|
||||||
|
<h3 className="text-lg">{t('Get started')}</h3>
|
||||||
|
<GetStartedCheckList />
|
||||||
|
{step > OnboardingStep.ONBOARDING_DEPOSIT_STEP && (
|
||||||
|
<TradingAnchorButton
|
||||||
|
href={Links[Routes.HOME]()}
|
||||||
|
onClick={() => dismiss()}
|
||||||
|
intent={Intent.Info}
|
||||||
|
>
|
||||||
|
{t('Start trading')}
|
||||||
|
</TradingAnchorButton>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { marketsWithDataProvider } from '@vegaprotocol/markets';
|
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
|
||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { Links, Routes } from '../../pages/client-router';
|
import { Links, Routes } from '../../pages/client-router';
|
||||||
import { useGlobalStore } from '../../stores';
|
import { useGlobalStore } from '../../stores';
|
||||||
|
import { useTopTradedMarkets } from '../../lib/hooks/use-top-traded-markets';
|
||||||
|
|
||||||
|
// The home pages only purpose is to redirect to the users last market,
|
||||||
|
// the top traded if they are new, or fall back to the list of markets.
|
||||||
|
// Thats why we just render a loader here
|
||||||
export const Home = () => {
|
export const Home = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
// The default market selected in the platform behind the overlay
|
const { data } = useTopTradedMarkets();
|
||||||
// should be the oldest market that is currently trading in continuous mode(i.e. not in auction).
|
|
||||||
const { data, error, loading } = useDataProvider({
|
|
||||||
dataProvider: marketsWithDataProvider,
|
|
||||||
variables: undefined,
|
|
||||||
});
|
|
||||||
const update = useGlobalStore((store) => store.update);
|
|
||||||
const marketId = useGlobalStore((store) => store.marketId);
|
const marketId = useGlobalStore((store) => store.marketId);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -32,12 +28,11 @@ export const Home = () => {
|
|||||||
navigate(Links[Routes.MARKETS]());
|
navigate(Links[Routes.MARKETS]());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [marketId, data, navigate, update]);
|
}, [marketId, data, navigate]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer data={data} loading={loading} error={error}>
|
<Splash>
|
||||||
{/* Render a loading and error state but we will redirect if markets are found */}
|
<Loader />
|
||||||
{null}
|
</Splash>
|
||||||
</AsyncRenderer>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { TradePanels } from './trade-panels';
|
|||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { Links, Routes } from '../../pages/client-router';
|
import { Links, Routes } from '../../pages/client-router';
|
||||||
import { ViewType, useSidebar } from '../../components/sidebar';
|
import { ViewType, useSidebar } from '../../components/sidebar';
|
||||||
|
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||||
|
|
||||||
const calculatePrice = (markPrice?: string, decimalPlaces?: number) => {
|
const calculatePrice = (markPrice?: string, decimalPlaces?: number) => {
|
||||||
return markPrice && decimalPlaces
|
return markPrice && decimalPlaces
|
||||||
@@ -58,7 +59,9 @@ const TitleUpdater = ({
|
|||||||
export const MarketPage = () => {
|
export const MarketPage = () => {
|
||||||
const { marketId } = useParams();
|
const { marketId } = useParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { init, view, setView } = useSidebar();
|
const currentRouteId = useGetCurrentRouteId();
|
||||||
|
const { setViews, getView } = useSidebar();
|
||||||
|
const view = getView(currentRouteId);
|
||||||
const { screenSize } = useScreenDimensions();
|
const { screenSize } = useScreenDimensions();
|
||||||
const largeScreen = ['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize);
|
const largeScreen = ['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize);
|
||||||
const update = useGlobalStore((store) => store.update);
|
const update = useGlobalStore((store) => store.update);
|
||||||
@@ -72,12 +75,11 @@ export const MarketPage = () => {
|
|||||||
}
|
}
|
||||||
}, [update, lastMarketId, data?.id]);
|
}, [update, lastMarketId, data?.id]);
|
||||||
|
|
||||||
// Make sidebar open on deal ticket by default
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (init && view === null) {
|
if (largeScreen && view === undefined) {
|
||||||
setView({ type: ViewType.Order });
|
setViews({ type: ViewType.Order }, currentRouteId);
|
||||||
}
|
}
|
||||||
}, [init, view, setView]);
|
}, [setViews, view, currentRouteId, largeScreen]);
|
||||||
|
|
||||||
const tradeView = useMemo(() => {
|
const tradeView = useMemo(() => {
|
||||||
if (largeScreen) {
|
if (largeScreen) {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ const MainGrid = memo(
|
|||||||
<Tabs storageKey="console-trade-grid-main-left">
|
<Tabs storageKey="console-trade-grid-main-left">
|
||||||
<Tab
|
<Tab
|
||||||
id="chart"
|
id="chart"
|
||||||
|
overflowHidden
|
||||||
name={t('Chart')}
|
name={t('Chart')}
|
||||||
menu={<TradingViews.candles.menu />}
|
menu={<TradingViews.candles.menu />}
|
||||||
>
|
>
|
||||||
@@ -72,7 +73,7 @@ const MainGrid = memo(
|
|||||||
</ResizableGridPanel>
|
</ResizableGridPanel>
|
||||||
<ResizableGridPanel
|
<ResizableGridPanel
|
||||||
minSize={200}
|
minSize={200}
|
||||||
preferredSize={sizesMiddle[1] || 300}
|
preferredSize={sizesMiddle[1] || 275}
|
||||||
>
|
>
|
||||||
<TradeGridChild>
|
<TradeGridChild>
|
||||||
<Tabs storageKey="console-trade-grid-main-right">
|
<Tabs storageKey="console-trade-grid-main-right">
|
||||||
@@ -180,7 +181,7 @@ const TradeGridChild = ({ children }: TradeGridChildProps) => {
|
|||||||
{({ width, height }) => (
|
{({ width, height }) => (
|
||||||
<div
|
<div
|
||||||
style={{ width, height }}
|
style={{ width, height }}
|
||||||
className="border border-default rounded-sm"
|
className="border rounded-sm border-default"
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { act, render, screen, within, waitFor } from '@testing-library/react';
|
import { act, render, screen, within } from '@testing-library/react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { Closed } from './closed';
|
import { Closed } from './closed';
|
||||||
import { MarketStateMapping, PropertyKeyType } from '@vegaprotocol/types';
|
import { MarketStateMapping, PropertyKeyType } from '@vegaprotocol/types';
|
||||||
@@ -10,55 +10,21 @@ import type {
|
|||||||
OracleSpecDataConnectionQuery,
|
OracleSpecDataConnectionQuery,
|
||||||
MarketsDataQuery,
|
MarketsDataQuery,
|
||||||
MarketsQuery,
|
MarketsQuery,
|
||||||
SuccessorMarketIdsQuery,
|
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import {
|
import {
|
||||||
OracleSpecDataConnectionDocument,
|
OracleSpecDataConnectionDocument,
|
||||||
MarketsDataDocument,
|
MarketsDataDocument,
|
||||||
MarketsDocument,
|
MarketsDocument,
|
||||||
SuccessorMarketIdsDocument,
|
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||||
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
import { FLAGS } from '@vegaprotocol/environment';
|
|
||||||
import {
|
import {
|
||||||
createMarketFragment,
|
createMarketFragment,
|
||||||
marketsQuery,
|
marketsQuery,
|
||||||
marketsDataQuery,
|
marketsDataQuery,
|
||||||
createMarketsDataFragment,
|
createMarketsDataFragment,
|
||||||
} from '@vegaprotocol/mock';
|
} from '@vegaprotocol/mock';
|
||||||
import type { FeatureFlags } from '@vegaprotocol/environment';
|
|
||||||
|
|
||||||
jest.mock('@vegaprotocol/markets', () => ({
|
|
||||||
...jest.requireActual('@vegaprotocol/markets'),
|
|
||||||
useSuccessorMarket: (marketId: string) =>
|
|
||||||
marketId === 'include-0'
|
|
||||||
? {
|
|
||||||
data: {
|
|
||||||
id: 'successorMarketID',
|
|
||||||
state: 'STATE_ACTIVE',
|
|
||||||
tradableInstrument: {
|
|
||||||
instrument: {
|
|
||||||
name: 'Successor Market Name',
|
|
||||||
code: 'SuccessorCode',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: { data: undefined },
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock('@vegaprotocol/environment', () => {
|
|
||||||
const actual = jest.requireActual('@vegaprotocol/environment');
|
|
||||||
return {
|
|
||||||
...actual,
|
|
||||||
FLAGS: {
|
|
||||||
...actual.FLAGS,
|
|
||||||
SUCCESSOR_MARKETS: true,
|
|
||||||
} as FeatureFlags,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Closed', () => {
|
describe('Closed', () => {
|
||||||
let originalNow: typeof Date.now;
|
let originalNow: typeof Date.now;
|
||||||
@@ -218,10 +184,8 @@ describe('Closed', () => {
|
|||||||
const headers = screen.getAllByRole('columnheader');
|
const headers = screen.getAllByRole('columnheader');
|
||||||
const expectedHeaders = [
|
const expectedHeaders = [
|
||||||
'Market',
|
'Market',
|
||||||
'Description',
|
|
||||||
'Status',
|
'Status',
|
||||||
'Settlement date',
|
'Settlement date',
|
||||||
'Successor market',
|
|
||||||
'Best bid',
|
'Best bid',
|
||||||
'Best offer',
|
'Best offer',
|
||||||
'Mark price',
|
'Mark price',
|
||||||
@@ -235,10 +199,8 @@ describe('Closed', () => {
|
|||||||
const cells = screen.getAllByRole('gridcell');
|
const cells = screen.getAllByRole('gridcell');
|
||||||
const expectedValues = [
|
const expectedValues = [
|
||||||
market.tradableInstrument.instrument.code,
|
market.tradableInstrument.instrument.code,
|
||||||
market.tradableInstrument.instrument.name,
|
|
||||||
MarketStateMapping[market.state],
|
MarketStateMapping[market.state],
|
||||||
'3 days ago',
|
'3 days ago',
|
||||||
'-',
|
|
||||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||||
addDecimalsFormatNumber(marketsData.bestBidPrice, market.decimalPlaces),
|
addDecimalsFormatNumber(marketsData.bestBidPrice, market.decimalPlaces),
|
||||||
addDecimalsFormatNumber(
|
addDecimalsFormatNumber(
|
||||||
@@ -340,43 +302,26 @@ describe('Closed', () => {
|
|||||||
.getAllByRole('gridcell')
|
.getAllByRole('gridcell')
|
||||||
.filter((cell) => cell.getAttribute('col-id') === 'code')
|
.filter((cell) => cell.getAttribute('col-id') === 'code')
|
||||||
.map((cell) => {
|
.map((cell) => {
|
||||||
const marketId = within(cell)
|
const marketCode = within(cell).getByTestId('stack-cell-primary');
|
||||||
.getByTestId('market-code')
|
return marketCode.textContent;
|
||||||
.getAttribute('data-market-id');
|
|
||||||
return marketId;
|
|
||||||
});
|
});
|
||||||
expect(cells).toEqual(expectedRows.map((m) => m.node.id));
|
expect(cells).toEqual(
|
||||||
|
expectedRows.map((m) => m.node.tradableInstrument.instrument.code)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('successor marked should be visible', async () => {
|
it('successor marked should be visible', async () => {
|
||||||
const mixedMarkets = [
|
const marketsWithSuccessorID = [
|
||||||
{
|
{
|
||||||
__typename: 'MarketEdge' as const,
|
__typename: 'MarketEdge' as const,
|
||||||
node: createMarketFragment({
|
node: createMarketFragment({
|
||||||
id: 'include-0',
|
id: 'include-0',
|
||||||
state: MarketState.STATE_SETTLED,
|
state: MarketState.STATE_SETTLED,
|
||||||
|
successorMarketID: 'successor',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
__typename: 'MarketEdge' as const,
|
|
||||||
node: {
|
|
||||||
...createMarketFragment({
|
|
||||||
id: 'successorMarketID',
|
|
||||||
state: MarketState.STATE_ACTIVE,
|
|
||||||
}),
|
|
||||||
tradableInstrument: {
|
|
||||||
...createMarketFragment().tradableInstrument,
|
|
||||||
instrument: {
|
|
||||||
...createMarketFragment().tradableInstrument.instrument,
|
|
||||||
id: 'successorAssset',
|
|
||||||
name: 'Successor Market Name',
|
|
||||||
code: 'SuccessorCode',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
const mixedMarketsMock: MockedResponse<MarketsQuery> = {
|
const mockWithSuccessors: MockedResponse<MarketsQuery> = {
|
||||||
request: {
|
request: {
|
||||||
query: MarketsDocument,
|
query: MarketsDocument,
|
||||||
},
|
},
|
||||||
@@ -384,42 +329,17 @@ describe('Closed', () => {
|
|||||||
data: {
|
data: {
|
||||||
marketsConnection: {
|
marketsConnection: {
|
||||||
__typename: 'MarketConnection',
|
__typename: 'MarketConnection',
|
||||||
edges: mixedMarkets,
|
edges: marketsWithSuccessorID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const successorMarketsMock: MockedResponse<SuccessorMarketIdsQuery> = {
|
|
||||||
request: {
|
await act(async () => {
|
||||||
query: SuccessorMarketIdsDocument,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
marketsConnection: {
|
|
||||||
__typename: 'MarketConnection',
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
id: 'include-0',
|
|
||||||
successorMarketID: 'successorMarketID',
|
|
||||||
parentMarketID: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
await act(() => {
|
|
||||||
render(
|
render(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<MockedProvider
|
<MockedProvider
|
||||||
mocks={[
|
mocks={[mockWithSuccessors, marketsDataMock, oracleDataMock]}
|
||||||
mixedMarketsMock,
|
|
||||||
marketsDataMock,
|
|
||||||
oracleDataMock,
|
|
||||||
successorMarketsMock,
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
<VegaWalletContext.Provider
|
<VegaWalletContext.Provider
|
||||||
value={{ pubKey } as VegaWalletContextShape}
|
value={{ pubKey } as VegaWalletContextShape}
|
||||||
@@ -431,122 +351,15 @@ describe('Closed', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() => {
|
const container = within(
|
||||||
expect(
|
document.querySelector('.ag-center-cols-container') as HTMLElement
|
||||||
screen.getByRole('button', { name: /^SuccessorCode/ })
|
);
|
||||||
).toBeInTheDocument();
|
const cell = container.getAllByRole('gridcell', {
|
||||||
});
|
name: (_name, element) => element.getAttribute('col-id') === 'code',
|
||||||
expect(
|
})[0];
|
||||||
screen.getByRole('columnheader', {
|
|
||||||
name: (_name, element) =>
|
|
||||||
element.getAttribute('col-id') === 'successorMarket',
|
|
||||||
})
|
|
||||||
).toBeInTheDocument();
|
|
||||||
screen
|
|
||||||
.getAllByRole('gridcell', {
|
|
||||||
name: (_name, element) =>
|
|
||||||
element.getAttribute('col-id') === 'successorMarket',
|
|
||||||
})
|
|
||||||
.forEach((element) => {
|
|
||||||
expect(element.querySelector('[title="Future"]')?.textContent).toEqual(
|
|
||||||
'Futr'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('feature flag should hide successors', async () => {
|
expect(within(cell).getByTestId('stack-cell-secondary')).toHaveTextContent(
|
||||||
const mockedFlags = jest.mocked(FLAGS);
|
'PRNT'
|
||||||
mockedFlags.SUCCESSOR_MARKETS = false;
|
|
||||||
|
|
||||||
const mixedMarkets = [
|
|
||||||
{
|
|
||||||
__typename: 'MarketEdge' as const,
|
|
||||||
node: createMarketFragment({
|
|
||||||
id: 'include-0',
|
|
||||||
state: MarketState.STATE_SETTLED,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
__typename: 'MarketEdge' as const,
|
|
||||||
node: {
|
|
||||||
...createMarketFragment({
|
|
||||||
id: 'successorMarketID',
|
|
||||||
state: MarketState.STATE_ACTIVE,
|
|
||||||
}),
|
|
||||||
tradableInstrument: {
|
|
||||||
...createMarketFragment().tradableInstrument,
|
|
||||||
instrument: {
|
|
||||||
...createMarketFragment().tradableInstrument.instrument,
|
|
||||||
id: 'successorAssset',
|
|
||||||
name: 'Successor Market Name',
|
|
||||||
code: 'SuccessorCode',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const mixedMarketsMock: MockedResponse<MarketsQuery> = {
|
|
||||||
request: {
|
|
||||||
query: MarketsDocument,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
marketsConnection: {
|
|
||||||
__typename: 'MarketConnection',
|
|
||||||
edges: mixedMarkets,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const successorMarketsMock: MockedResponse<SuccessorMarketIdsQuery> = {
|
|
||||||
request: {
|
|
||||||
query: SuccessorMarketIdsDocument,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
marketsConnection: {
|
|
||||||
__typename: 'MarketConnection',
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
id: 'include-0',
|
|
||||||
successorMarketID: 'successorMarketID',
|
|
||||||
parentMarketID: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
render(
|
|
||||||
<MemoryRouter>
|
|
||||||
<MockedProvider
|
|
||||||
mocks={[
|
|
||||||
mixedMarketsMock,
|
|
||||||
marketsDataMock,
|
|
||||||
oracleDataMock,
|
|
||||||
successorMarketsMock,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<VegaWalletContext.Provider
|
|
||||||
value={{ pubKey } as VegaWalletContextShape}
|
|
||||||
>
|
|
||||||
<Closed />
|
|
||||||
</VegaWalletContext.Provider>
|
|
||||||
</MockedProvider>
|
|
||||||
</MemoryRouter>
|
|
||||||
);
|
);
|
||||||
await waitFor(() => {
|
|
||||||
expect(
|
|
||||||
screen.getByRole('columnheader', {
|
|
||||||
name: (_name, element) =>
|
|
||||||
element.getAttribute('col-id') === 'settlementDate',
|
|
||||||
})
|
|
||||||
).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
screen.getAllByRole('columnheader').forEach((element) => {
|
|
||||||
expect(element.getAttribute('col-id')).not.toEqual('successorMarket');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,13 +4,10 @@ import type {
|
|||||||
VegaICellRendererParams,
|
VegaICellRendererParams,
|
||||||
VegaValueFormatterParams,
|
VegaValueFormatterParams,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import {
|
import { AgGridLazy as AgGrid, COL_DEFS } from '@vegaprotocol/datagrid';
|
||||||
AgGridLazy as AgGrid,
|
|
||||||
COL_DEFS,
|
|
||||||
MarketNameCell,
|
|
||||||
} from '@vegaprotocol/datagrid';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { ProductType } from '@vegaprotocol/types';
|
||||||
import { MarketState, MarketStateMapping } from '@vegaprotocol/types';
|
import { MarketState, MarketStateMapping } from '@vegaprotocol/types';
|
||||||
import {
|
import {
|
||||||
addDecimalsFormatNumber,
|
addDecimalsFormatNumber,
|
||||||
@@ -20,17 +17,13 @@ import type {
|
|||||||
DataSourceFilterFragment,
|
DataSourceFilterFragment,
|
||||||
MarketMaybeWithData,
|
MarketMaybeWithData,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import {
|
import { closedMarketsWithDataProvider } from '@vegaprotocol/markets';
|
||||||
MarketActionsDropdown,
|
|
||||||
closedMarketsWithDataProvider,
|
|
||||||
} from '@vegaprotocol/markets';
|
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
import type { ColDef } from 'ag-grid-community';
|
|
||||||
import { FLAGS } from '@vegaprotocol/environment';
|
|
||||||
import { SettlementDateCell } from './settlement-date-cell';
|
import { SettlementDateCell } from './settlement-date-cell';
|
||||||
import { SettlementPriceCell } from './settlement-price-cell';
|
import { SettlementPriceCell } from './settlement-price-cell';
|
||||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
import { SuccessorMarketRenderer } from './successor-market-cell';
|
import { MarketActionsDropdown } from './market-table-actions';
|
||||||
|
import { MarketCodeCell } from './market-code-cell';
|
||||||
|
|
||||||
type SettlementAsset =
|
type SettlementAsset =
|
||||||
MarketMaybeWithData['tradableInstrument']['instrument']['product']['settlementAsset'];
|
MarketMaybeWithData['tradableInstrument']['instrument']['product']['settlementAsset'];
|
||||||
@@ -51,7 +44,9 @@ interface Row {
|
|||||||
setlementDataSourceFilter: DataSourceFilterFragment | undefined;
|
setlementDataSourceFilter: DataSourceFilterFragment | undefined;
|
||||||
tradingTerminationOracleId: string;
|
tradingTerminationOracleId: string;
|
||||||
settlementAsset: SettlementAsset;
|
settlementAsset: SettlementAsset;
|
||||||
productType: string;
|
productType: ProductType | undefined;
|
||||||
|
successorMarketID: string | null | undefined;
|
||||||
|
parentMarketID: string | null | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Closed = () => {
|
export const Closed = () => {
|
||||||
@@ -95,16 +90,19 @@ export const Closed = () => {
|
|||||||
tradingTerminationOracleId:
|
tradingTerminationOracleId:
|
||||||
instrument.product.dataSourceSpecForTradingTermination.id,
|
instrument.product.dataSourceSpecForTradingTermination.id,
|
||||||
settlementAsset: instrument.product.settlementAsset,
|
settlementAsset: instrument.product.settlementAsset,
|
||||||
productType: instrument.product.__typename || '',
|
productType: instrument.product.__typename,
|
||||||
|
successorMarketID: market.successorMarketID,
|
||||||
|
parentMarketID: market.parentMarketID,
|
||||||
};
|
};
|
||||||
|
|
||||||
return row;
|
return row;
|
||||||
});
|
});
|
||||||
return (
|
|
||||||
<div className="h-full relative">
|
return <ClosedMarketsDataGrid rowData={rowData} error={error} />;
|
||||||
<ClosedMarketsDataGrid rowData={rowData} error={error} />
|
};
|
||||||
</div>
|
|
||||||
);
|
const components = {
|
||||||
|
MarketCodeCell,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ClosedMarketsDataGrid = ({
|
const ClosedMarketsDataGrid = ({
|
||||||
@@ -117,15 +115,11 @@ const ClosedMarketsDataGrid = ({
|
|||||||
const openAssetDialog = useAssetDetailsDialogStore((store) => store.open);
|
const openAssetDialog = useAssetDetailsDialogStore((store) => store.open);
|
||||||
|
|
||||||
const colDefs = useMemo(() => {
|
const colDefs = useMemo(() => {
|
||||||
const cols: ColDef[] = compact([
|
return [
|
||||||
{
|
{
|
||||||
headerName: t('Market'),
|
headerName: t('Market'),
|
||||||
field: 'code',
|
field: 'code',
|
||||||
cellRenderer: 'MarketNameCell',
|
cellRenderer: 'MarketCodeCell',
|
||||||
},
|
|
||||||
{
|
|
||||||
headerName: t('Description'),
|
|
||||||
field: 'name',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headerName: t('Status'),
|
headerName: t('Status'),
|
||||||
@@ -176,12 +170,6 @@ const ClosedMarketsDataGrid = ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
FLAGS.SUCCESSOR_MARKETS && {
|
|
||||||
headerName: t('Successor market'),
|
|
||||||
field: 'id',
|
|
||||||
colId: 'successorMarket',
|
|
||||||
cellRenderer: 'SuccessorMarketRenderer',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
headerName: t('Best bid'),
|
headerName: t('Best bid'),
|
||||||
field: 'bestBidPrice',
|
field: 'bestBidPrice',
|
||||||
@@ -263,12 +251,13 @@ const ClosedMarketsDataGrid = ({
|
|||||||
<MarketActionsDropdown
|
<MarketActionsDropdown
|
||||||
marketId={data.id}
|
marketId={data.id}
|
||||||
assetId={data.settlementAsset.id}
|
assetId={data.settlementAsset.id}
|
||||||
|
successorMarketID={data.successorMarketID}
|
||||||
|
parentMarketID={data.parentMarketID}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
];
|
||||||
return cols;
|
|
||||||
}, [openAssetDialog]);
|
}, [openAssetDialog]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -276,8 +265,9 @@ const ClosedMarketsDataGrid = ({
|
|||||||
rowData={rowData}
|
rowData={rowData}
|
||||||
columnDefs={colDefs}
|
columnDefs={colDefs}
|
||||||
getRowId={({ data }) => data.id}
|
getRowId={({ data }) => data.id}
|
||||||
components={{ SuccessorMarketRenderer, MarketNameCell }}
|
|
||||||
overlayNoRowsTemplate={error ? error.message : t('No markets')}
|
overlayNoRowsTemplate={error ? error.message : t('No markets')}
|
||||||
|
components={components}
|
||||||
|
rowHeight={45}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { ProductTypeShortName } from '@vegaprotocol/types';
|
||||||
|
import type { MarketCodeCellProps } from './market-code-cell';
|
||||||
|
import { MarketCodeCell } from './market-code-cell';
|
||||||
|
|
||||||
|
describe('MarketCodeCell', () => {
|
||||||
|
const renderComponent = (props: MarketCodeCellProps) => {
|
||||||
|
return render(<MarketCodeCell {...props} />);
|
||||||
|
};
|
||||||
|
|
||||||
|
it('renders SCCR if the market is a successor', () => {
|
||||||
|
const productType = 'Future';
|
||||||
|
const code = 'code';
|
||||||
|
const props = {
|
||||||
|
value: 'code',
|
||||||
|
data: {
|
||||||
|
productType,
|
||||||
|
parentMarketID: 'foo',
|
||||||
|
successorMarketID: undefined,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
renderComponent(props);
|
||||||
|
expect(screen.getByTestId('stack-cell-primary')).toHaveTextContent(code);
|
||||||
|
expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent(
|
||||||
|
ProductTypeShortName[productType]
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent(
|
||||||
|
'SCCR'
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('stack-cell-secondary')).not.toHaveTextContent(
|
||||||
|
'PRNT'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders PRNT if the market is a parent', () => {
|
||||||
|
const productType = 'Future';
|
||||||
|
const code = 'code';
|
||||||
|
const props = {
|
||||||
|
value: 'code',
|
||||||
|
data: {
|
||||||
|
productType,
|
||||||
|
parentMarketID: undefined,
|
||||||
|
successorMarketID: 'foo',
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
renderComponent(props);
|
||||||
|
expect(screen.getByTestId('stack-cell-primary')).toHaveTextContent(code);
|
||||||
|
expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent(
|
||||||
|
ProductTypeShortName[productType]
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent(
|
||||||
|
'PRNT'
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('stack-cell-secondary')).not.toHaveTextContent(
|
||||||
|
'SCCR'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders both SCCR and PRNT if the market is both a parent and a successor', () => {
|
||||||
|
const productType = 'Future';
|
||||||
|
const code = 'code';
|
||||||
|
const props = {
|
||||||
|
value: 'code',
|
||||||
|
data: {
|
||||||
|
productType,
|
||||||
|
parentMarketID: 'foo',
|
||||||
|
successorMarketID: 'bar',
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
renderComponent(props);
|
||||||
|
expect(screen.getByTestId('stack-cell-primary')).toHaveTextContent(code);
|
||||||
|
expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent(
|
||||||
|
ProductTypeShortName[productType]
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent(
|
||||||
|
'PRNT'
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent(
|
||||||
|
'SCCR'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import compact from 'lodash/compact';
|
||||||
|
import type { ProductType } from '@vegaprotocol/types';
|
||||||
|
import { ProductTypeMapping, ProductTypeShortName } from '@vegaprotocol/types';
|
||||||
|
import { StackedCell } from '@vegaprotocol/datagrid';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
export interface MarketCodeCellProps {
|
||||||
|
value: string | undefined; // market code
|
||||||
|
data: {
|
||||||
|
productType: ProductType | undefined;
|
||||||
|
parentMarketID: string | null | undefined;
|
||||||
|
successorMarketID: string | null | undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MarketCodeCell = ({ value, data }: MarketCodeCellProps) => {
|
||||||
|
if (!value || !data || !data.productType) return null;
|
||||||
|
|
||||||
|
const infoSpanClasses =
|
||||||
|
'mr-1 pr-1 uppercase border-r last:pr-0 last:mr-0 last:border-r-0 border-vega-clight-200 dark:border-vega-cdark-200';
|
||||||
|
|
||||||
|
const info = compact([
|
||||||
|
<span
|
||||||
|
className={infoSpanClasses}
|
||||||
|
key="productType"
|
||||||
|
title={ProductTypeMapping[data.productType]}
|
||||||
|
>
|
||||||
|
{ProductTypeShortName[data.productType]}
|
||||||
|
</span>,
|
||||||
|
data.parentMarketID && (
|
||||||
|
<span
|
||||||
|
className={infoSpanClasses}
|
||||||
|
key="successor"
|
||||||
|
title={t('Successor of a market')}
|
||||||
|
>
|
||||||
|
{t('SCCR')}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
data.successorMarketID && (
|
||||||
|
<span
|
||||||
|
className={infoSpanClasses}
|
||||||
|
key="parent"
|
||||||
|
title={t('Parent of a market')}
|
||||||
|
>
|
||||||
|
{t('PRNT')}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return <StackedCell primary={value} secondary={info} />;
|
||||||
|
};
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import type { TypedDataAgGrid } from '@vegaprotocol/datagrid';
|
||||||
|
import { AgGridLazy as AgGrid, PriceFlashCell } from '@vegaprotocol/datagrid';
|
||||||
|
import type { MarketMaybeWithData } from '@vegaprotocol/markets';
|
||||||
|
import { useColumnDefs } from './use-column-defs';
|
||||||
|
|
||||||
|
export const getRowId = ({ data }: { data: { id: string } }) => data.id;
|
||||||
|
|
||||||
|
const defaultColDef = {
|
||||||
|
sortable: true,
|
||||||
|
filter: true,
|
||||||
|
filterParams: { buttons: ['reset'] },
|
||||||
|
};
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
PriceFlashCell,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = TypedDataAgGrid<MarketMaybeWithData>;
|
||||||
|
|
||||||
|
export const MarketListTable = (props: Props) => {
|
||||||
|
const columnDefs = useColumnDefs();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AgGrid
|
||||||
|
getRowId={getRowId}
|
||||||
|
defaultColDef={defaultColDef}
|
||||||
|
columnDefs={columnDefs}
|
||||||
|
components={components}
|
||||||
|
rowHeight={45}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MarketListTable;
|
||||||
+27
@@ -9,14 +9,21 @@ import {
|
|||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { DApp, EXPLORER_MARKET, useLinks } from '@vegaprotocol/environment';
|
import { DApp, EXPLORER_MARKET, useLinks } from '@vegaprotocol/environment';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { Links, Routes } from '../../pages/client-router';
|
||||||
|
|
||||||
export const MarketActionsDropdown = ({
|
export const MarketActionsDropdown = ({
|
||||||
marketId,
|
marketId,
|
||||||
assetId,
|
assetId,
|
||||||
|
successorMarketID,
|
||||||
|
parentMarketID,
|
||||||
}: {
|
}: {
|
||||||
marketId: string;
|
marketId: string;
|
||||||
assetId: string;
|
assetId: string;
|
||||||
|
successorMarketID: string | null | undefined;
|
||||||
|
parentMarketID: string | null | undefined;
|
||||||
}) => {
|
}) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
const open = useAssetDetailsDialogStore((store) => store.open);
|
const open = useAssetDetailsDialogStore((store) => store.open);
|
||||||
const linkCreator = useLinks(DApp.Explorer);
|
const linkCreator = useLinks(DApp.Explorer);
|
||||||
|
|
||||||
@@ -42,6 +49,26 @@ export const MarketActionsDropdown = ({
|
|||||||
<VegaIcon name={VegaIconNames.INFO} size={16} />
|
<VegaIcon name={VegaIconNames.INFO} size={16} />
|
||||||
{t('View settlement asset details')}
|
{t('View settlement asset details')}
|
||||||
</TradingDropdownItem>
|
</TradingDropdownItem>
|
||||||
|
{parentMarketID && (
|
||||||
|
<TradingDropdownItem
|
||||||
|
onClick={() => {
|
||||||
|
navigate(Links[Routes.MARKET](parentMarketID));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<VegaIcon name={VegaIconNames.EYE} size={16} />
|
||||||
|
{t('View parent market')}
|
||||||
|
</TradingDropdownItem>
|
||||||
|
)}
|
||||||
|
{successorMarketID && (
|
||||||
|
<TradingDropdownItem
|
||||||
|
onClick={() => {
|
||||||
|
navigate(Links[Routes.MARKET](successorMarketID));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<VegaIcon name={VegaIconNames.EYE} size={16} />
|
||||||
|
{t('View successor market')}
|
||||||
|
</TradingDropdownItem>
|
||||||
|
)}
|
||||||
</ActionsDropdown>
|
</ActionsDropdown>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
Tab,
|
Tab,
|
||||||
TradingAnchorButton,
|
TradingAnchorButton,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { Markets } from './markets';
|
import { OpenMarkets } from './open-markets';
|
||||||
import { Proposed } from './proposed';
|
import { Proposed } from './proposed';
|
||||||
import { usePageTitleStore } from '../../stores';
|
import { usePageTitleStore } from '../../stores';
|
||||||
import { Closed } from './closed';
|
import { Closed } from './closed';
|
||||||
@@ -21,8 +21,8 @@ export const MarketsPage = () => {
|
|||||||
updateTitle: store.updateTitle,
|
updateTitle: store.updateTitle,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const tokenLink = useLinks(DApp.Token);
|
const governanceLink = useLinks(DApp.Governance);
|
||||||
const externalLink = tokenLink(TOKEN_NEW_MARKET_PROPOSAL);
|
const externalLink = governanceLink(TOKEN_NEW_MARKET_PROPOSAL);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateTitle(titlefy(['Markets']));
|
updateTitle(titlefy(['Markets']));
|
||||||
@@ -33,7 +33,7 @@ export const MarketsPage = () => {
|
|||||||
<div className="h-full my-1 border rounded-sm border-default">
|
<div className="h-full my-1 border rounded-sm border-default">
|
||||||
<Tabs storageKey="console-markets">
|
<Tabs storageKey="console-markets">
|
||||||
<Tab id="open-markets" name={t('Open markets')}>
|
<Tab id="open-markets" name={t('Open markets')}>
|
||||||
<Markets />
|
<OpenMarkets />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="proposed-markets"
|
id="proposed-markets"
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { MarketsContainer } from '@vegaprotocol/markets';
|
|
||||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
|
||||||
import { SuccessorMarketRenderer } from './successor-market-cell';
|
|
||||||
|
|
||||||
export const Markets = () => {
|
|
||||||
const handleOnSelect = useMarketClickHandler();
|
|
||||||
return (
|
|
||||||
<MarketsContainer
|
|
||||||
onSelect={handleOnSelect}
|
|
||||||
SuccessorMarketRenderer={SuccessorMarketRenderer}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
|
import type { MarketMaybeWithData } from '@vegaprotocol/markets';
|
||||||
|
import { marketListProvider } from '@vegaprotocol/markets';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { CellClickedEvent } from 'ag-grid-community';
|
||||||
|
import MarketListTable from './market-list-table';
|
||||||
|
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||||
|
import { Interval } from '@vegaprotocol/types';
|
||||||
|
import { useYesterday } from '@vegaprotocol/react-helpers';
|
||||||
|
|
||||||
|
const POLLING_TIME = 2000;
|
||||||
|
|
||||||
|
export const OpenMarkets = () => {
|
||||||
|
const handleOnSelect = useMarketClickHandler();
|
||||||
|
const yesterday = useYesterday();
|
||||||
|
const { data, error, reload } = useDataProvider({
|
||||||
|
dataProvider: marketListProvider,
|
||||||
|
variables: {
|
||||||
|
since: new Date(yesterday).toISOString(),
|
||||||
|
interval: Interval.INTERVAL_I1H,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
reload();
|
||||||
|
}, POLLING_TIME);
|
||||||
|
return () => {
|
||||||
|
clearInterval(interval);
|
||||||
|
};
|
||||||
|
}, [reload]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MarketListTable
|
||||||
|
rowData={data}
|
||||||
|
onCellClicked={({
|
||||||
|
data,
|
||||||
|
column,
|
||||||
|
event,
|
||||||
|
}: CellClickedEvent<MarketMaybeWithData>) => {
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
// prevent navigating to the market page if any of the below cells are clicked
|
||||||
|
// event.preventDefault or event.stopPropagation dont seem to apply for aggird
|
||||||
|
const colId = column.getColId();
|
||||||
|
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
'tradableInstrument.instrument.product.settlementAsset.symbol',
|
||||||
|
'market-actions',
|
||||||
|
].includes(colId)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore metaKey exists
|
||||||
|
handleOnSelect(data.id, event ? event.metaKey : false);
|
||||||
|
}}
|
||||||
|
overlayNoRowsTemplate={error ? error.message : t('No markets')}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
|
import { Icon } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import type { IconName } from '@blueprintjs/icons';
|
||||||
|
import type { Market } from '@vegaprotocol/markets';
|
||||||
|
import {
|
||||||
|
getMatchingOracleProvider,
|
||||||
|
getVerifiedStatusIcon,
|
||||||
|
useOracleProofs,
|
||||||
|
} from '@vegaprotocol/markets';
|
||||||
|
|
||||||
|
export const OracleStatus = ({
|
||||||
|
dataSourceSpecForSettlementData,
|
||||||
|
dataSourceSpecForTradingTermination,
|
||||||
|
}: Pick<
|
||||||
|
Market['tradableInstrument']['instrument']['product'],
|
||||||
|
'dataSourceSpecForSettlementData' | 'dataSourceSpecForTradingTermination'
|
||||||
|
>) => {
|
||||||
|
const { ORACLE_PROOFS_URL } = useEnvironment();
|
||||||
|
const { data: providers } = useOracleProofs(ORACLE_PROOFS_URL);
|
||||||
|
|
||||||
|
if (providers) {
|
||||||
|
const settlementDataProvider = getMatchingOracleProvider(
|
||||||
|
dataSourceSpecForSettlementData.data,
|
||||||
|
providers
|
||||||
|
);
|
||||||
|
const tradingTerminationDataProvider = getMatchingOracleProvider(
|
||||||
|
dataSourceSpecForTradingTermination.data,
|
||||||
|
providers
|
||||||
|
);
|
||||||
|
let maliciousOracleProvider = null;
|
||||||
|
|
||||||
|
if (settlementDataProvider?.oracle.status !== 'GOOD') {
|
||||||
|
maliciousOracleProvider = settlementDataProvider;
|
||||||
|
} else if (tradingTerminationDataProvider?.oracle.status !== 'GOOD') {
|
||||||
|
maliciousOracleProvider = tradingTerminationDataProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!maliciousOracleProvider) return null;
|
||||||
|
|
||||||
|
const { icon } = getVerifiedStatusIcon(maliciousOracleProvider);
|
||||||
|
|
||||||
|
return <Icon size={3} name={icon as IconName} className="ml-1" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { useMarketsMapProvider } from '@vegaprotocol/markets';
|
||||||
|
|
||||||
|
export const ParentMarketCell = ({
|
||||||
|
value,
|
||||||
|
}: {
|
||||||
|
value: string; // parentMarketId
|
||||||
|
}) => {
|
||||||
|
const { data, loading } = useMarketsMapProvider();
|
||||||
|
|
||||||
|
if (loading) return null;
|
||||||
|
|
||||||
|
if (!data || !data[value]) return <span>-</span>;
|
||||||
|
|
||||||
|
return <div>{data[value].tradableInstrument.instrument.code}</div>;
|
||||||
|
};
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
import { ProposalsList } from '@vegaprotocol/proposals';
|
import { ProposalsList } from '@vegaprotocol/proposals';
|
||||||
import { SuccessorMarketRenderer } from './successor-market-cell';
|
import { ParentMarketCell } from './parent-market-cell';
|
||||||
|
|
||||||
|
const cellRenderers = {
|
||||||
|
ParentMarketCell,
|
||||||
|
};
|
||||||
|
|
||||||
export const Proposed = () => {
|
export const Proposed = () => {
|
||||||
return <ProposalsList SuccessorMarketRenderer={SuccessorMarketRenderer} />;
|
return <ProposalsList cellRenderers={cellRenderers} />;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,190 +0,0 @@
|
|||||||
import { render, screen, act, waitFor } from '@testing-library/react';
|
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
|
||||||
import userEvent from '@testing-library/user-event';
|
|
||||||
import type { Market } from '@vegaprotocol/markets';
|
|
||||||
import { SuccessorMarketRenderer } from './successor-market-cell';
|
|
||||||
import {
|
|
||||||
MarketsDocument,
|
|
||||||
SuccessorMarketIdsDocument,
|
|
||||||
} from '@vegaprotocol/markets';
|
|
||||||
import { createMarketFragment } from '@vegaprotocol/mock';
|
|
||||||
|
|
||||||
const mockSuccessorsQuery = [
|
|
||||||
{
|
|
||||||
id: 'market1',
|
|
||||||
parentMarketID: 'parentMarket1',
|
|
||||||
successorMarketID: 'successorMarket1',
|
|
||||||
},
|
|
||||||
{ id: 'market2', parentMarketID: 'parentMarket2' },
|
|
||||||
{ id: 'market3', successorMarketID: 'successorMarket3' },
|
|
||||||
];
|
|
||||||
const parentMarket1 = {
|
|
||||||
id: 'parentMarket1',
|
|
||||||
tradableInstrument: {
|
|
||||||
instrument: { code: 'code parent 1', id: '1' },
|
|
||||||
},
|
|
||||||
} as unknown as Market;
|
|
||||||
const successorMarket1 = {
|
|
||||||
id: 'successorMarket1',
|
|
||||||
tradableInstrument: {
|
|
||||||
instrument: { code: 'code successor 1', id: '2' },
|
|
||||||
},
|
|
||||||
} as unknown as Market;
|
|
||||||
const parentMarket2 = {
|
|
||||||
id: 'parentMarket2',
|
|
||||||
tradableInstrument: {
|
|
||||||
instrument: { code: 'code parent 2', id: '3' },
|
|
||||||
},
|
|
||||||
} as unknown as Market;
|
|
||||||
const successorMarket3 = {
|
|
||||||
id: 'successorMarket3',
|
|
||||||
tradableInstrument: {
|
|
||||||
instrument: { code: 'code successor 3', id: '4' },
|
|
||||||
},
|
|
||||||
} as unknown as Market;
|
|
||||||
|
|
||||||
const mockMarkets = [
|
|
||||||
parentMarket1,
|
|
||||||
successorMarket1,
|
|
||||||
parentMarket2,
|
|
||||||
successorMarket3,
|
|
||||||
];
|
|
||||||
|
|
||||||
const mockClickHandler = jest.fn();
|
|
||||||
jest.mock('../../lib/hooks/use-market-click-handler', () => ({
|
|
||||||
useMarketClickHandler: jest.fn().mockImplementation(() => mockClickHandler),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const marketMock = {
|
|
||||||
request: {
|
|
||||||
query: MarketsDocument,
|
|
||||||
variables: undefined,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
marketsConnection: {
|
|
||||||
edges: mockMarkets.map((item) => ({
|
|
||||||
node: {
|
|
||||||
...createMarketFragment(item),
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const successorMock = {
|
|
||||||
request: {
|
|
||||||
query: SuccessorMarketIdsDocument,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
marketsConnection: {
|
|
||||||
edges: mockSuccessorsQuery.map((item) => ({
|
|
||||||
node: {
|
|
||||||
...item,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const mocks = [marketMock, successorMock];
|
|
||||||
|
|
||||||
describe('SuccessorMarketRenderer', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
it('should properly rendered successor market', async () => {
|
|
||||||
const successorValue = 'market1';
|
|
||||||
render(
|
|
||||||
<MockedProvider mocks={[...mocks]}>
|
|
||||||
<SuccessorMarketRenderer value={successorValue} />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
expect(screen.getByText('code successor 1')).toBeInTheDocument();
|
|
||||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button'));
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(mockClickHandler).toHaveBeenCalledWith('successorMarket1', false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should properly rendered parent market', async () => {
|
|
||||||
const successorValue = 'market1';
|
|
||||||
render(
|
|
||||||
<MockedProvider mocks={[...mocks]}>
|
|
||||||
<SuccessorMarketRenderer value={successorValue} parent />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
expect(screen.getByText('code parent 1')).toBeInTheDocument();
|
|
||||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button'));
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(mockClickHandler).toHaveBeenCalledWith('parentMarket1', false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should properly rendered only parent market', async () => {
|
|
||||||
const successorValue = 'market2';
|
|
||||||
const { rerender } = render(
|
|
||||||
<MockedProvider mocks={[...mocks]}>
|
|
||||||
<SuccessorMarketRenderer value={successorValue} parent />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
expect(screen.getByText('code parent 2')).toBeInTheDocument();
|
|
||||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
|
||||||
await userEvent.click(screen.getByRole('button'));
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(mockClickHandler).toHaveBeenCalledWith('parentMarket2', false);
|
|
||||||
});
|
|
||||||
|
|
||||||
rerender(
|
|
||||||
<MockedProvider mocks={[...mocks]}>
|
|
||||||
<SuccessorMarketRenderer value={successorValue} />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByText('-')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
it('should properly rendered only successor market', async () => {
|
|
||||||
const successorValue = 'market3';
|
|
||||||
const { rerender } = render(
|
|
||||||
<MockedProvider mocks={[...mocks]}>
|
|
||||||
<SuccessorMarketRenderer value={successorValue} />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
expect(screen.getByText('code successor 3')).toBeInTheDocument();
|
|
||||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button'));
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(mockClickHandler).toHaveBeenCalledWith('successorMarket3', false);
|
|
||||||
});
|
|
||||||
|
|
||||||
await act(() => {
|
|
||||||
rerender(
|
|
||||||
<MockedProvider mocks={[...mocks]}>
|
|
||||||
<SuccessorMarketRenderer value={successorValue} parent />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
expect(screen.getByText('-')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { MarketNameCell } from '@vegaprotocol/datagrid';
|
|
||||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
|
||||||
import { marketProvider, useSuccessorMarketIds } from '@vegaprotocol/markets';
|
|
||||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
|
||||||
|
|
||||||
export const SuccessorMarketRenderer = ({
|
|
||||||
value,
|
|
||||||
parent,
|
|
||||||
}: {
|
|
||||||
value: string;
|
|
||||||
parent?: boolean;
|
|
||||||
}) => {
|
|
||||||
const successors = useSuccessorMarketIds(value);
|
|
||||||
const onMarketClick = useMarketClickHandler();
|
|
||||||
|
|
||||||
const lookupValue = successors
|
|
||||||
? parent
|
|
||||||
? successors.parentMarketID
|
|
||||||
: successors.successorMarketID
|
|
||||||
: '';
|
|
||||||
|
|
||||||
const { data } = useDataProvider({
|
|
||||||
dataProvider: marketProvider,
|
|
||||||
variables: {
|
|
||||||
marketId: lookupValue || '',
|
|
||||||
},
|
|
||||||
skip: !lookupValue,
|
|
||||||
});
|
|
||||||
|
|
||||||
return data ? (
|
|
||||||
<MarketNameCell
|
|
||||||
value={data.tradableInstrument.instrument.code}
|
|
||||||
data={data}
|
|
||||||
onMarketClick={onMarketClick}
|
|
||||||
productType={data.tradableInstrument.instrument?.product.__typename}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
'-'
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import type { ColDef, ValueFormatterParams } from 'ag-grid-community';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type {
|
||||||
|
VegaICellRendererParams,
|
||||||
|
VegaValueFormatterParams,
|
||||||
|
VegaValueGetterParams,
|
||||||
|
} from '@vegaprotocol/datagrid';
|
||||||
|
import { COL_DEFS, SetFilter } from '@vegaprotocol/datagrid';
|
||||||
|
import * as Schema from '@vegaprotocol/types';
|
||||||
|
import { addDecimalsFormatNumber, toBigNum } from '@vegaprotocol/utils';
|
||||||
|
import { ButtonLink, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
|
import type {
|
||||||
|
MarketMaybeWithData,
|
||||||
|
MarketMaybeWithDataAndCandles,
|
||||||
|
} from '@vegaprotocol/markets';
|
||||||
|
import { MarketActionsDropdown } from './market-table-actions';
|
||||||
|
import { calcCandleVolume } from '@vegaprotocol/markets';
|
||||||
|
import { MarketCodeCell } from './market-code-cell';
|
||||||
|
|
||||||
|
const { MarketTradingMode, AuctionTrigger } = Schema;
|
||||||
|
|
||||||
|
export const useColumnDefs = () => {
|
||||||
|
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||||
|
return useMemo<ColDef[]>(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
headerName: t('Market'),
|
||||||
|
field: 'tradableInstrument.instrument.code',
|
||||||
|
flex: 2,
|
||||||
|
cellRenderer: ({
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
}: VegaICellRendererParams<
|
||||||
|
MarketMaybeWithData,
|
||||||
|
'tradableInstrument.instrument.code'
|
||||||
|
>) => (
|
||||||
|
<MarketCodeCell
|
||||||
|
value={value}
|
||||||
|
data={{
|
||||||
|
productType:
|
||||||
|
data?.tradableInstrument.instrument.product.__typename,
|
||||||
|
successorMarketID: data?.successorMarketID,
|
||||||
|
parentMarketID: data?.parentMarketID,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Description'),
|
||||||
|
field: 'tradableInstrument.instrument.name',
|
||||||
|
flex: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Trading mode'),
|
||||||
|
field: 'tradingMode',
|
||||||
|
cellRenderer: ({
|
||||||
|
data,
|
||||||
|
}: VegaICellRendererParams<MarketMaybeWithData, 'data'>) => {
|
||||||
|
if (!data?.data) return '-';
|
||||||
|
const { trigger, marketTradingMode } = data.data;
|
||||||
|
|
||||||
|
const withTriggerInfo =
|
||||||
|
marketTradingMode ===
|
||||||
|
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
|
||||||
|
trigger &&
|
||||||
|
trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED;
|
||||||
|
|
||||||
|
if (withTriggerInfo) {
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
description={`${Schema.MarketTradingModeMapping[marketTradingMode]}
|
||||||
|
- ${Schema.AuctionTriggerMapping[trigger]}`}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
{Schema.MarketTradingModeMapping[marketTradingMode]}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Schema.MarketTradingModeMapping[marketTradingMode];
|
||||||
|
},
|
||||||
|
filter: SetFilter,
|
||||||
|
filterParams: {
|
||||||
|
set: Schema.MarketTradingModeMapping,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Status'),
|
||||||
|
field: 'state',
|
||||||
|
valueFormatter: ({
|
||||||
|
data,
|
||||||
|
}: VegaValueFormatterParams<MarketMaybeWithData, 'state'>) => {
|
||||||
|
return data?.state ? Schema.MarketStateMapping[data.state] : '-';
|
||||||
|
},
|
||||||
|
filter: SetFilter,
|
||||||
|
filterParams: {
|
||||||
|
set: Schema.MarketStateMapping,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Mark price'),
|
||||||
|
field: 'data.markPrice',
|
||||||
|
type: 'rightAligned',
|
||||||
|
cellRenderer: 'PriceFlashCell',
|
||||||
|
filter: 'agNumberColumnFilter',
|
||||||
|
valueGetter: ({ data }: VegaValueGetterParams<MarketMaybeWithData>) => {
|
||||||
|
return data?.data?.markPrice === undefined
|
||||||
|
? undefined
|
||||||
|
: toBigNum(data?.data?.markPrice, data.decimalPlaces).toNumber();
|
||||||
|
},
|
||||||
|
valueFormatter: ({
|
||||||
|
data,
|
||||||
|
}: VegaValueFormatterParams<MarketMaybeWithData, 'data.markPrice'>) =>
|
||||||
|
data?.data?.bestOfferPrice === undefined
|
||||||
|
? '-'
|
||||||
|
: addDecimalsFormatNumber(data.data.markPrice, data.decimalPlaces),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('24h volume'),
|
||||||
|
type: 'rightAligned',
|
||||||
|
field: 'data.candles',
|
||||||
|
valueGetter: ({
|
||||||
|
data,
|
||||||
|
}: VegaValueGetterParams<MarketMaybeWithDataAndCandles>) => {
|
||||||
|
if (!data) return 0;
|
||||||
|
const candles = data?.candles;
|
||||||
|
const vol = candles ? calcCandleVolume(candles) : '0';
|
||||||
|
return Number(vol);
|
||||||
|
},
|
||||||
|
valueFormatter: ({
|
||||||
|
data,
|
||||||
|
}: ValueFormatterParams<MarketMaybeWithDataAndCandles, 'candles'>) => {
|
||||||
|
const candles = data?.candles;
|
||||||
|
const vol = candles ? calcCandleVolume(candles) : '0';
|
||||||
|
const volume =
|
||||||
|
data && vol && vol !== '0'
|
||||||
|
? addDecimalsFormatNumber(vol, data.positionDecimalPlaces)
|
||||||
|
: '0.00';
|
||||||
|
return volume;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Settlement asset'),
|
||||||
|
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
||||||
|
cellRenderer: ({
|
||||||
|
data,
|
||||||
|
}: VegaICellRendererParams<
|
||||||
|
MarketMaybeWithData,
|
||||||
|
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
||||||
|
>) => {
|
||||||
|
const value =
|
||||||
|
data?.tradableInstrument.instrument.product.settlementAsset;
|
||||||
|
return value ? (
|
||||||
|
<ButtonLink
|
||||||
|
onClick={(e) => {
|
||||||
|
openAssetDetailsDialog(value.id, e.target as HTMLElement);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{value.symbol}
|
||||||
|
</ButtonLink>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Spread'),
|
||||||
|
field: 'data.bestBidPrice',
|
||||||
|
type: 'rightAligned',
|
||||||
|
filter: 'agNumberColumnFilter',
|
||||||
|
cellRenderer: 'PriceFlashCell',
|
||||||
|
valueGetter: ({ data }: VegaValueGetterParams<MarketMaybeWithData>) => {
|
||||||
|
if (!data || !data.data?.bestOfferPrice || !data.data?.bestBidPrice) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const offer = toBigNum(data.data.bestOfferPrice, data.decimalPlaces);
|
||||||
|
const bid = toBigNum(data.data.bestBidPrice, data.decimalPlaces);
|
||||||
|
|
||||||
|
const spread = offer.minus(bid).toNumber();
|
||||||
|
|
||||||
|
// The calculation above can result in '-0' being rendered after formatting
|
||||||
|
// so return Math.abs to remove it and just render '0'
|
||||||
|
if (spread === 0) {
|
||||||
|
return Math.abs(spread);
|
||||||
|
}
|
||||||
|
|
||||||
|
return spread;
|
||||||
|
},
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<
|
||||||
|
MarketMaybeWithData,
|
||||||
|
'data.bestBidPrice'
|
||||||
|
>) => {
|
||||||
|
if (!value) return '-';
|
||||||
|
return value.toString();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'market-actions',
|
||||||
|
field: 'id',
|
||||||
|
...COL_DEFS.actions,
|
||||||
|
cellRenderer: ({
|
||||||
|
data,
|
||||||
|
}: VegaICellRendererParams<MarketMaybeWithData>) => {
|
||||||
|
if (!data) return null;
|
||||||
|
return (
|
||||||
|
<MarketActionsDropdown
|
||||||
|
marketId={data.id}
|
||||||
|
assetId={
|
||||||
|
data.tradableInstrument.instrument.product.settlementAsset.id
|
||||||
|
}
|
||||||
|
successorMarketID={data.successorMarketID}
|
||||||
|
parentMarketID={data.parentMarketID}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[openAssetDetailsDialog]
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -23,6 +23,7 @@ import { ViewType, useSidebar } from '../../components/sidebar';
|
|||||||
import { AccountsMenu } from '../../components/accounts-menu';
|
import { AccountsMenu } from '../../components/accounts-menu';
|
||||||
import { DepositsMenu } from '../../components/deposits-menu';
|
import { DepositsMenu } from '../../components/deposits-menu';
|
||||||
import { WithdrawalsMenu } from '../../components/withdrawals-menu';
|
import { WithdrawalsMenu } from '../../components/withdrawals-menu';
|
||||||
|
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||||
|
|
||||||
const WithdrawalsIndicator = () => {
|
const WithdrawalsIndicator = () => {
|
||||||
const { ready } = useIncompleteWithdrawals();
|
const { ready } = useIncompleteWithdrawals();
|
||||||
@@ -37,7 +38,10 @@ const WithdrawalsIndicator = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Portfolio = () => {
|
export const Portfolio = () => {
|
||||||
const { init, view, setView } = useSidebar();
|
const currentRouteId = useGetCurrentRouteId();
|
||||||
|
const { getView, setViews } = useSidebar();
|
||||||
|
const view = getView(currentRouteId);
|
||||||
|
|
||||||
const { updateTitle } = usePageTitleStore((store) => ({
|
const { updateTitle } = usePageTitleStore((store) => ({
|
||||||
updateTitle: store.updateTitle,
|
updateTitle: store.updateTitle,
|
||||||
}));
|
}));
|
||||||
@@ -48,10 +52,10 @@ export const Portfolio = () => {
|
|||||||
|
|
||||||
// Make transfer sidebar open by default
|
// Make transfer sidebar open by default
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (init && view === null) {
|
if (view === undefined) {
|
||||||
setView({ type: ViewType.Transfer });
|
setViews({ type: ViewType.Transfer }, currentRouteId);
|
||||||
}
|
}
|
||||||
}, [init, view, setView]);
|
}, [view, setViews, currentRouteId]);
|
||||||
|
|
||||||
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'portfolio' });
|
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'portfolio' });
|
||||||
const wrapperClasses = 'p-0.5 h-full max-h-full flex flex-col';
|
const wrapperClasses = 'p-0.5 h-full max-h-full flex flex-col';
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import { Input, InputError } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import type { FieldValues } from 'react-hook-form';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { Button } from './buttons';
|
||||||
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
|
export const ApplyCodeForm = () => {
|
||||||
|
const { isReadOnly, pubKey, sendTx } = useVegaWallet();
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
setValue,
|
||||||
|
setError,
|
||||||
|
} = useForm();
|
||||||
|
const [params] = useSearchParams();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const code = params.get('code');
|
||||||
|
if (code) setValue('code', code);
|
||||||
|
}, [params, setValue]);
|
||||||
|
|
||||||
|
const onSubmit = ({ code }: FieldValues) => {
|
||||||
|
if (isReadOnly || !pubKey || !code || code.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTx(pubKey, {
|
||||||
|
applyReferralCode: {
|
||||||
|
id: code as string,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
// TODO: Do something with response
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
setError('code', {
|
||||||
|
type: 'required',
|
||||||
|
message: 'Your code has been rejected',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-1/2 mx-auto">
|
||||||
|
<h3 className="mb-5 text-xl text-center uppercase calt">
|
||||||
|
Apply a referral code
|
||||||
|
</h3>
|
||||||
|
<p className="mb-6 text-center">Enter a referral code</p>
|
||||||
|
<form
|
||||||
|
className={classNames('w-full flex flex-col gap-3', {
|
||||||
|
'animate-shake': Boolean(errors.code),
|
||||||
|
})}
|
||||||
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
|
>
|
||||||
|
<label className="flex-grow">
|
||||||
|
<span className="block mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
Your referral code
|
||||||
|
</span>
|
||||||
|
<Input
|
||||||
|
hasError={Boolean(errors.code)}
|
||||||
|
{...register('code', {
|
||||||
|
required: 'You have to provide a code to apply it.',
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<Button
|
||||||
|
disabled={isReadOnly || !pubKey}
|
||||||
|
className="w-full"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
Apply
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
{errors.code && (
|
||||||
|
<InputError>{errors.code.message?.toString()}</InputError>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import { Intent, TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import type { ComponentProps, ButtonHTMLAttributes } from 'react';
|
||||||
|
import { forwardRef } from 'react';
|
||||||
|
import { NavLink } from 'react-router-dom';
|
||||||
|
|
||||||
|
type RainbowButtonProps = {
|
||||||
|
variant?: 'full' | 'border';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RainbowButton = ({
|
||||||
|
variant = 'full',
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: RainbowButtonProps & ButtonHTMLAttributes<HTMLButtonElement>) => (
|
||||||
|
<button
|
||||||
|
className={classNames(
|
||||||
|
'bg-rainbow hover:bg-none hover:bg-rainbow enabled:hover:bg-vega-pink-500 rounded-lg overflow-hidden disabled:opacity-40',
|
||||||
|
{
|
||||||
|
'px-5 py-3 text-white': variant === 'full',
|
||||||
|
'p-[0.125rem]': variant === 'border',
|
||||||
|
},
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={classNames({
|
||||||
|
'bg-white dark:bg-vega-cdark-900 text-black dark:text-white px-5 py-3 rounded-[0.35rem] overflow-hidden':
|
||||||
|
variant === 'border',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
|
||||||
|
const RAINBOW_TAB_STYLE = classNames(
|
||||||
|
'inline-block',
|
||||||
|
'bg-vega-clight-500 dark:bg-vega-cdark-500 hover:bg-vega-clight-400 dark:hover:bg-vega-cdark-400',
|
||||||
|
'data-[state="active"]:text-white data-[state="active"]:bg-rainbow data-[state="active"]:hover:bg-none data-[state="active"]:hover:bg-vega-pink-500 dark:data-[state="active"]:hover:bg-vega-pink-500',
|
||||||
|
'[&.active]:text-white [&.active]:bg-rainbow [&.active]:hover:bg-none [&.active]:hover:bg-vega-pink-500 dark:[&.active]:hover:bg-vega-pink-500',
|
||||||
|
'px-5 py-3',
|
||||||
|
'first:rounded-tl-lg last:rounded-tr-lg'
|
||||||
|
);
|
||||||
|
|
||||||
|
export const RainbowTabButton = forwardRef<
|
||||||
|
HTMLButtonElement,
|
||||||
|
ButtonHTMLAttributes<HTMLButtonElement>
|
||||||
|
>(({ children, ...props }, ref) => (
|
||||||
|
<button ref={ref} className={RAINBOW_TAB_STYLE} {...props}>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
));
|
||||||
|
RainbowTabButton.displayName = 'RainbowTabButton';
|
||||||
|
|
||||||
|
export const RainbowTabLink = ({
|
||||||
|
to,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: ComponentProps<typeof NavLink>) => (
|
||||||
|
<NavLink to={to} className={RAINBOW_TAB_STYLE} {...props}>
|
||||||
|
{children}
|
||||||
|
</NavLink>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Button = forwardRef<
|
||||||
|
HTMLButtonElement,
|
||||||
|
ComponentProps<typeof TradingButton>
|
||||||
|
>(({ children, intent, type, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<TradingButton
|
||||||
|
ref={ref}
|
||||||
|
intent={intent || type === 'submit' ? Intent.Primary : Intent.None}
|
||||||
|
type={type}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</TradingButton>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
Button.displayName = 'TradingButton';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export const BORDER_COLOR = 'border-vega-clight-500 dark:border-vega-cdark-500';
|
||||||
|
export const GRADIENT =
|
||||||
|
'bg-gradient-to-b from-vega-clight-800 dark:from-vega-cdark-800 to-transparent';
|
||||||
|
|
||||||
|
export const SKY_BACKGROUND =
|
||||||
|
'bg-[url(/sky-light.png)] dark:bg-[url(/sky-dark.png)] bg-[40%_0px] bg-[length:1440px] bg-no-repeat';
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
import {
|
||||||
|
useVegaWallet,
|
||||||
|
useVegaWalletDialogStore,
|
||||||
|
determineId,
|
||||||
|
} from '@vegaprotocol/wallet';
|
||||||
|
import { RainbowButton } from './buttons';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import {
|
||||||
|
CopyWithTooltip,
|
||||||
|
Dialog,
|
||||||
|
ExternalLink,
|
||||||
|
InputError,
|
||||||
|
Intent,
|
||||||
|
TradingAnchorButton,
|
||||||
|
TradingButton,
|
||||||
|
VegaIcon,
|
||||||
|
VegaIconNames,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { gql, useQuery } from '@apollo/client';
|
||||||
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
|
import { DApp, TokenStaticLinks, useLinks } from '@vegaprotocol/environment';
|
||||||
|
|
||||||
|
const CREATE_CODE_QUERY = gql`
|
||||||
|
query CreateCode($partyId: ID!) {
|
||||||
|
party(id: $partyId) {
|
||||||
|
stakingSummary {
|
||||||
|
currentStakeAvailable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
networkParameter(key: "referralProgram.minStakedVegaTokens") {
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const CreateCodeContainer = () => {
|
||||||
|
const { pubKey } = useVegaWallet();
|
||||||
|
const { data, loading } = useQuery(CREATE_CODE_QUERY, {
|
||||||
|
variables: { partyId: pubKey || '' },
|
||||||
|
skip: !pubKey,
|
||||||
|
// TOOD: remove when network params available
|
||||||
|
errorPolicy: 'ignore',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loading) return null;
|
||||||
|
|
||||||
|
const requiredStake = data?.networkParameter?.value || '0';
|
||||||
|
const currentStakeAvailable =
|
||||||
|
data?.party?.stakingSummary.currentStakeAvailable || '0';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CreateCodeForm
|
||||||
|
currentStakeAvailable={currentStakeAvailable}
|
||||||
|
requiredStake={requiredStake}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CreateCodeForm = ({
|
||||||
|
currentStakeAvailable,
|
||||||
|
requiredStake,
|
||||||
|
}: {
|
||||||
|
currentStakeAvailable: string;
|
||||||
|
requiredStake: string;
|
||||||
|
}) => {
|
||||||
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
|
const openWalletDialog = useVegaWalletDialogStore(
|
||||||
|
(store) => store.openVegaWalletDialog
|
||||||
|
);
|
||||||
|
const { pubKey } = useVegaWallet();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-1/2 mx-auto">
|
||||||
|
<h3 className="mb-5 text-xl text-center uppercase calt">
|
||||||
|
Create a referral code
|
||||||
|
</h3>
|
||||||
|
<p className="mb-6 text-center">
|
||||||
|
Generate a referral code to share with your friends and start earning
|
||||||
|
commission.
|
||||||
|
</p>
|
||||||
|
<div className="mb-5">
|
||||||
|
<div className="text-center">
|
||||||
|
<RainbowButton
|
||||||
|
variant="border"
|
||||||
|
onClick={() => {
|
||||||
|
if (pubKey) {
|
||||||
|
setDialogOpen(true);
|
||||||
|
} else {
|
||||||
|
openWalletDialog();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{pubKey ? 'Create a referral code' : 'Connect wallet'}
|
||||||
|
</RainbowButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Dialog
|
||||||
|
title="Create a referral code"
|
||||||
|
open={dialogOpen}
|
||||||
|
onChange={() => setDialogOpen(false)}
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<CreateCodeDialog
|
||||||
|
currentStakeAvailable={currentStakeAvailable}
|
||||||
|
setDialogOpen={setDialogOpen}
|
||||||
|
requiredStake={requiredStake}
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CreateCodeDialog = ({
|
||||||
|
setDialogOpen,
|
||||||
|
currentStakeAvailable,
|
||||||
|
requiredStake,
|
||||||
|
}: {
|
||||||
|
setDialogOpen: (open: boolean) => void;
|
||||||
|
currentStakeAvailable: string;
|
||||||
|
requiredStake: string;
|
||||||
|
}) => {
|
||||||
|
const createLink = useLinks(DApp.Governance);
|
||||||
|
const { isReadOnly, pubKey, sendTx } = useVegaWallet();
|
||||||
|
const [err, setErr] = useState<string | null>(null);
|
||||||
|
const [code, setCode] = useState<string | null>(null);
|
||||||
|
const [status, setStatus] = useState<
|
||||||
|
'idle' | 'loading' | 'success' | 'error'
|
||||||
|
>('idle');
|
||||||
|
|
||||||
|
const onSubmit = () => {
|
||||||
|
if (isReadOnly || !pubKey) {
|
||||||
|
setErr('Not connected');
|
||||||
|
} else {
|
||||||
|
setErr(null);
|
||||||
|
setStatus('loading');
|
||||||
|
setCode(null);
|
||||||
|
sendTx(pubKey, {
|
||||||
|
createReferralSet: {
|
||||||
|
isTeam: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (!res) {
|
||||||
|
setErr(`Invalid response: ${JSON.stringify(res)}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const code = determineId(res.signature);
|
||||||
|
setCode(code);
|
||||||
|
setStatus('success');
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (err.message.includes('user rejected')) {
|
||||||
|
setStatus('idle');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setStatus('error');
|
||||||
|
setErr(err.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getButtonProps = () => {
|
||||||
|
if (status === 'idle' || status === 'error') {
|
||||||
|
return {
|
||||||
|
children: 'Generate code',
|
||||||
|
onClick: () => onSubmit(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === 'loading') {
|
||||||
|
return {
|
||||||
|
children: 'Confirm in wallet...',
|
||||||
|
disabled: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === 'success') {
|
||||||
|
return {
|
||||||
|
children: 'Close',
|
||||||
|
intent: Intent.Success,
|
||||||
|
onClick: () => setDialogOpen(false),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Add when network parameters are updated
|
||||||
|
|
||||||
|
if (
|
||||||
|
currentStakeAvailable === '0' ||
|
||||||
|
BigInt(currentStakeAvailable) < BigInt(requiredStake)
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<p>
|
||||||
|
You need at least {addDecimalsFormatNumber(requiredStake, 18)} VEGA
|
||||||
|
staked to generate a referral code and participate in the referral
|
||||||
|
program.
|
||||||
|
</p>
|
||||||
|
<TradingAnchorButton
|
||||||
|
href={createLink(TokenStaticLinks.ASSOCIATE)}
|
||||||
|
intent={Intent.Primary}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Stake some $VEGA now
|
||||||
|
</TradingAnchorButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
{(status === 'idle' || status === 'loading' || status === 'error') && (
|
||||||
|
<p>
|
||||||
|
Generate a referral code to share with your friends aand start enaring
|
||||||
|
commission.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
{status === 'success' && code && (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="flex-1 min-w-0 p-2 text-sm rounded bg-vega-clight-700 dark:bg-vega-cdark-700">
|
||||||
|
<p className="overflow-hidden whitespace-nowrap text-ellipsis">
|
||||||
|
{code}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<CopyWithTooltip text={code}>
|
||||||
|
<TradingButton
|
||||||
|
className="text-sm no-underline"
|
||||||
|
icon={<VegaIcon name={VegaIconNames.COPY} />}
|
||||||
|
>
|
||||||
|
<span>Copy</span>
|
||||||
|
</TradingButton>
|
||||||
|
</CopyWithTooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<TradingButton
|
||||||
|
fill={true}
|
||||||
|
intent={Intent.Primary}
|
||||||
|
{...getButtonProps()}
|
||||||
|
/>
|
||||||
|
{err && <InputError>{err}</InputError>}
|
||||||
|
{/* TODO: Add links */}
|
||||||
|
<div className="flex justify-center pt-5 mt-2 text-sm border-t gap-4 text-default border-default">
|
||||||
|
<ExternalLink>About the referral program</ExternalLink>
|
||||||
|
<ExternalLink>Disclaimer</ExternalLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { isRouteErrorResponse, useNavigate, useRouteError } from 'react-router';
|
||||||
|
import { RainbowButton } from './buttons';
|
||||||
|
import { AnimatedDudeWithWire } from './graphics/dude';
|
||||||
|
import { LayoutWithSky } from './layout';
|
||||||
|
|
||||||
|
export const ErrorBoundary = () => {
|
||||||
|
const error = useRouteError();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const title = isRouteErrorResponse(error)
|
||||||
|
? `${error.status} ${error.statusText}`
|
||||||
|
: 'Something went wrong';
|
||||||
|
|
||||||
|
const code = isRouteErrorResponse(error) ? error.status : 0;
|
||||||
|
|
||||||
|
const messages: Record<number, string> = {
|
||||||
|
0: 'An unknown error occurred.',
|
||||||
|
404: "The page you're looking for doesn't exists.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LayoutWithSky className="pt-32">
|
||||||
|
<div
|
||||||
|
aria-hidden
|
||||||
|
className="absolute top-64 right-[220px] md:right-[340px] max-sm:hidden"
|
||||||
|
>
|
||||||
|
<AnimatedDudeWithWire className="animate-spin" />
|
||||||
|
</div>
|
||||||
|
<h1 className="text-6xl font-alpha calt mb-10">{title}</h1>
|
||||||
|
|
||||||
|
{Object.keys(messages).includes(code.toString()) ? (
|
||||||
|
<p className="text-lg mb-10">{messages[code]}</p>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<p className="text-lg mb-10">
|
||||||
|
<RainbowButton
|
||||||
|
onClick={() => navigate('..')}
|
||||||
|
variant="border"
|
||||||
|
className="text-xs"
|
||||||
|
>
|
||||||
|
Go back and try again
|
||||||
|
</RainbowButton>
|
||||||
|
</p>
|
||||||
|
</LayoutWithSky>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import type { HTMLAttributes } from 'react';
|
||||||
|
|
||||||
|
export const Dude = ({ className }: HTMLAttributes<SVGElement>) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="41"
|
||||||
|
height="47"
|
||||||
|
viewBox="0 0 41 47"
|
||||||
|
fill="none"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M21.1895 0.298767L5.08827 27.4101L8.96133 29.7103L4.36099 37.4564L8.23404 39.7566L12.8344 32.0105L16.7074 34.3107L12.1071 42.0568L15.9801 44.3569L20.5805 36.6108L24.4535 38.911L40.5547 11.7996L21.1895 0.298767Z"
|
||||||
|
className="fill-black dark:fill-white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M35.9346 15.1683L20.4424 5.96765L14.3086 16.2958L29.8008 25.4965L35.9346 15.1683Z"
|
||||||
|
className="fill-white dark:fill-black"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M25.646 17.7895L23.064 16.2561L21.5305 18.8381L24.1126 20.3716L25.646 17.7895Z"
|
||||||
|
className="fill-black dark:fill-white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M29.7612 16.7412L27.1792 15.2077L25.6458 17.7898L28.2278 19.3232L29.7612 16.7412Z"
|
||||||
|
className="fill-black dark:fill-white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M33.877 15.6925L31.2949 14.159L29.7615 16.7411L32.3435 18.2745L33.877 15.6925Z"
|
||||||
|
className="fill-black dark:fill-white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M29.0342 26.7874L26.4521 25.2539L24.9187 27.836L27.5007 29.3694L29.0342 26.7874Z"
|
||||||
|
fill="#FF077F"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Wire = ({ className }: HTMLAttributes<SVGElement>) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="157"
|
||||||
|
height="88"
|
||||||
|
viewBox="0 0 157 88"
|
||||||
|
fill="none"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M109.398 6.12235C127.37 -3.81898 146.791 1.45045 153.465 14.307C160.138 27.1636 154.195 43.9948 140.438 52.1164C126.68 60.238 105.767 54.9998 84.9212 43.464C64.0752 31.9281 32.2412 6.42016 18.8175 24.185C6.90871 40.719 41.9332 68.4495 29.2664 82.7049C23.187 88.4974 11.1379 88.2645 0.968295 80.3398"
|
||||||
|
className="stroke-black dark:stroke-white"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
strokeMiterlimit="10"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AnimatedDudeWithWire = ({ className }: { className?: string }) => (
|
||||||
|
<div className="relative">
|
||||||
|
<Wire className="absolute top-[25px]" />
|
||||||
|
<Dude
|
||||||
|
className={classNames(
|
||||||
|
'absolute left-[96px] animate-[wave_20s_ease-in-out_infinite]',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import { getNumberFormat } from '@vegaprotocol/utils';
|
||||||
|
import { addDays } from 'date-fns';
|
||||||
|
|
||||||
|
// TODO: Generate query
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const REFERRAL_PROGRAM_QUERY = gql`
|
||||||
|
query ReferralProgram {
|
||||||
|
currentReferralProgram {
|
||||||
|
id
|
||||||
|
version
|
||||||
|
endOfProgramTimestamp
|
||||||
|
windowLength
|
||||||
|
endedAt
|
||||||
|
benefitTiers {
|
||||||
|
minimumEpochs
|
||||||
|
minimumRunningNotionalTakerVolume
|
||||||
|
referralDiscountFactor
|
||||||
|
referralRewardFactor
|
||||||
|
}
|
||||||
|
stakingTiers {
|
||||||
|
minimumStakedTokens
|
||||||
|
referralRewardMultiplier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const useReferralProgram = () => {
|
||||||
|
// TODO: get real data
|
||||||
|
// const { data, loading, error } = useQuery(REFERRAL_PROGRAM_QUERY, {
|
||||||
|
// fetchPolicy: 'cache-and-network',
|
||||||
|
// });
|
||||||
|
|
||||||
|
const dummyData = {
|
||||||
|
currentReferralProgram: {
|
||||||
|
id: 'abc',
|
||||||
|
version: 1,
|
||||||
|
endOfProgramTimestamp: addDays(new Date(), 10).toISOString(),
|
||||||
|
windowLength: 10,
|
||||||
|
benefitTiers: [
|
||||||
|
{
|
||||||
|
minimumEpochs: 5,
|
||||||
|
minimumRunningNotionalTakerVolume: '30000',
|
||||||
|
referralDiscountFactor: '0.01',
|
||||||
|
referralRewardFactor: '0.01',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
minimumEpochs: 5,
|
||||||
|
minimumRunningNotionalTakerVolume: '20000',
|
||||||
|
referralDiscountFactor: '0.05',
|
||||||
|
referralRewardFactor: '0.05',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
minimumEpochs: 5,
|
||||||
|
minimumRunningNotionalTakerVolume: '10000',
|
||||||
|
referralDiscountFactor: '0.001',
|
||||||
|
referralRewardFactor: '0.001',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const benefitTiers = dummyData.currentReferralProgram.benefitTiers.map(
|
||||||
|
(t, i) => {
|
||||||
|
return {
|
||||||
|
tier: i + 1,
|
||||||
|
commission: Number(t.referralRewardFactor) * 100 + '%',
|
||||||
|
discount: Number(t.referralDiscountFactor) * 100 + '%',
|
||||||
|
volume: getNumberFormat(0).format(
|
||||||
|
Number(t.minimumRunningNotionalTakerVolume)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: return real loading, error values
|
||||||
|
return {
|
||||||
|
benefitTiers,
|
||||||
|
loading: false,
|
||||||
|
error: undefined,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { gql, useQuery } from '@apollo/client';
|
||||||
|
|
||||||
|
const REFERRAL_QUERY = gql`
|
||||||
|
query ReferralSets($partyId: ID!) {
|
||||||
|
referralSets(referrer: $partyId) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
referrer
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const REFEREES_QUERY = gql`
|
||||||
|
query ReferralSets($code: ID!) {
|
||||||
|
referralSetReferees(id: $code) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
referralSetId
|
||||||
|
refereeId
|
||||||
|
joinedAt
|
||||||
|
atEpoch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Fetches the current user's referral and then fetches all referees using
|
||||||
|
// the referral code
|
||||||
|
export const useReferral = (pubKey: string) => {
|
||||||
|
const {
|
||||||
|
data: referralData,
|
||||||
|
loading: referralLoading,
|
||||||
|
error: referralError,
|
||||||
|
} = useQuery(REFERRAL_QUERY, {
|
||||||
|
variables: {
|
||||||
|
partyId: pubKey,
|
||||||
|
},
|
||||||
|
fetchPolicy: 'cache-and-network',
|
||||||
|
});
|
||||||
|
|
||||||
|
// A user can only have 1 active referral program at a time
|
||||||
|
const referral = referralData?.referralSets.edges.length
|
||||||
|
? referralData.referralSets.edges[0].node
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: refereesData,
|
||||||
|
loading: refereesLoading,
|
||||||
|
error: refereesError,
|
||||||
|
} = useQuery(REFEREES_QUERY, {
|
||||||
|
variables: {
|
||||||
|
code: referral?.id,
|
||||||
|
},
|
||||||
|
skip: !referral?.id,
|
||||||
|
fetchPolicy: 'cache-and-network',
|
||||||
|
});
|
||||||
|
|
||||||
|
const referees = refereesData?.referralSetReferees.edges?.map(
|
||||||
|
// TODO: generate types
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
(e: any) => e.node
|
||||||
|
);
|
||||||
|
|
||||||
|
const data =
|
||||||
|
referral && refereesData
|
||||||
|
? {
|
||||||
|
code: referral.id,
|
||||||
|
referees,
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
// TODO: generate types after perps work is merged
|
||||||
|
data: data as
|
||||||
|
| {
|
||||||
|
code: string;
|
||||||
|
referees: Array<{
|
||||||
|
refereeId: string;
|
||||||
|
joinedAt: string;
|
||||||
|
atEpoch: number;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| undefined,
|
||||||
|
loading: referralLoading || refereesLoading,
|
||||||
|
error: referralError || refereesError,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { Table } from './table';
|
||||||
|
|
||||||
|
export const HowItWorksTable = () => (
|
||||||
|
<Table
|
||||||
|
className="bg-none bg-vega-clight-800 dark:bg-vega-cdark-800"
|
||||||
|
noHeader
|
||||||
|
noCollapse
|
||||||
|
columns={[{ name: 'number', className: 'px-0 pl-5' }, { name: 'step' }]}
|
||||||
|
data={[
|
||||||
|
{
|
||||||
|
number: (
|
||||||
|
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
1
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
step: 'Referrers generate a code assigned to their key via an on chain transaction',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
number: (
|
||||||
|
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
2
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
step: 'Anyone with the referral link can apply it to their key(s) of choice via an on chain transaction',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
number: (
|
||||||
|
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
3
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
step: 'Discounts are applied automatically during trading based on the key(s) used',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
number: (
|
||||||
|
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
4
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
step: 'Referrers earn commission based on a percentage of the taker fees their referees pay',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
number: (
|
||||||
|
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
5
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
step: 'The commission is taken from the infrastructure fee, maker fee, and liquidity provider fee, not from the referee',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
></Table>
|
||||||
|
);
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import { AnimatedDudeWithWire } from './graphics/dude';
|
||||||
|
|
||||||
|
export const LandingBanner = () => {
|
||||||
|
return (
|
||||||
|
<div className={classNames('relative mb-20')}>
|
||||||
|
<div className="">
|
||||||
|
<div
|
||||||
|
aria-hidden
|
||||||
|
className="absolute top-64 right-[220px] md:right-[340px] max-sm:hidden"
|
||||||
|
>
|
||||||
|
<AnimatedDudeWithWire />
|
||||||
|
</div>
|
||||||
|
<div className="pt-32 sm:w-[50%]">
|
||||||
|
<h1 className="text-6xl font-alpha calt mb-10">
|
||||||
|
Earn commission & stake rewards
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg mb-10">
|
||||||
|
Invite friends and earn commission in the form of Vega rewards from
|
||||||
|
the trading fees they pay. Stake those rewards to earn multipliers
|
||||||
|
on future rewards.
|
||||||
|
</p>
|
||||||
|
<p className="text-lg">
|
||||||
|
Any friends that join using the code will receive discounts off
|
||||||
|
trading fees.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import type { HTMLAttributes } from 'react';
|
||||||
|
import { SKY_BACKGROUND } from './constants';
|
||||||
|
import { Outlet } from 'react-router-dom';
|
||||||
|
|
||||||
|
export const Layout = ({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: HTMLAttributes<HTMLDivElement>) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'max-w-[1440px]',
|
||||||
|
'mx-auto px-16 md:px-32 pb-32',
|
||||||
|
'relative z-0',
|
||||||
|
'h-full overflow-auto',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children || <Outlet />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LayoutWithSky = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: HTMLAttributes<HTMLDivElement>) => {
|
||||||
|
return (
|
||||||
|
<div className={classNames('h-full', SKY_BACKGROUND)}>
|
||||||
|
<Layout className={className} {...props} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
import { Tile } from './tile';
|
||||||
|
import {
|
||||||
|
CopyWithTooltip,
|
||||||
|
Input,
|
||||||
|
VegaIcon,
|
||||||
|
VegaIconNames,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { Button, RainbowButton } from './buttons';
|
||||||
|
import { Tag } from './tag';
|
||||||
|
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||||
|
import { useReferral } from './hooks/use-referral';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
export const ReferralStatistics = () => {
|
||||||
|
const openWalletDialog = useVegaWalletDialogStore(
|
||||||
|
(store) => store.openVegaWalletDialog
|
||||||
|
);
|
||||||
|
const { pubKey } = useVegaWallet();
|
||||||
|
|
||||||
|
if (pubKey) {
|
||||||
|
return <ReferralStatisticsContainer pubKey={pubKey} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="text-center">
|
||||||
|
<RainbowButton variant="border" onClick={() => openWalletDialog()}>
|
||||||
|
Connect wallet
|
||||||
|
</RainbowButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ReferralStatisticsContainer = ({ pubKey }: { pubKey: string }) => {
|
||||||
|
const { data } = useReferral(pubKey);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-1 grid-rows-1 gap-5">
|
||||||
|
<div className="grid grid-cols-3 grid-rows-1 gap-5">
|
||||||
|
<Tile>
|
||||||
|
<h3 className="mb-1 text-4xl text-center">3</h3>
|
||||||
|
<p className="mb-3 text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
Your referral tier
|
||||||
|
</p>
|
||||||
|
<Tag className="mx-auto" color="purple">
|
||||||
|
10,000 until Tier 2
|
||||||
|
</Tag>
|
||||||
|
</Tile>
|
||||||
|
<Tile>
|
||||||
|
<h3 className="mb-1 text-4xl text-center">0.1%</h3>
|
||||||
|
<p className="mb-3 text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
Your commission
|
||||||
|
</p>
|
||||||
|
<Tag className="mx-auto" color="purple">
|
||||||
|
10,000 until 0.5%x
|
||||||
|
</Tag>
|
||||||
|
</Tile>
|
||||||
|
|
||||||
|
{data?.code ? (
|
||||||
|
<Tile variant="rainbow">
|
||||||
|
<h3 className="mb-1 text-lg calt">Your referral code</h3>
|
||||||
|
<p className="mb-3 text-sm text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
Share this code with friends
|
||||||
|
</p>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Input size={1} readOnly value={data.code} />
|
||||||
|
<CopyWithTooltip text={data.code}>
|
||||||
|
<Button
|
||||||
|
className="text-sm no-underline"
|
||||||
|
icon={<VegaIcon name={VegaIconNames.COPY} />}
|
||||||
|
>
|
||||||
|
<span>Copy</span>
|
||||||
|
</Button>
|
||||||
|
</CopyWithTooltip>
|
||||||
|
</div>
|
||||||
|
</Tile>
|
||||||
|
) : (
|
||||||
|
<Tile variant="rainbow">
|
||||||
|
<h3 className="mb-1 text-lg calt">
|
||||||
|
Create referral code to start earning rewards
|
||||||
|
</h3>
|
||||||
|
<p className="mb-3 text-sm text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
Invite friends and earn commission
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<Link to="create-code" className="underline underline-offset-4">
|
||||||
|
Create a referral code
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
</Tile>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-4 grid-rows-1 gap-5">
|
||||||
|
<Tile className="py-3">
|
||||||
|
<h3 className="mb-1 text-2xl text-center">10,000</h3>
|
||||||
|
<p className="text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
Your total trading volume
|
||||||
|
</p>
|
||||||
|
</Tile>
|
||||||
|
{data?.code && (
|
||||||
|
<Tile className="py-3">
|
||||||
|
<h3 className="mb-1 text-2xl text-center">
|
||||||
|
{data.referees.length}
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
{data.referees.length === 1
|
||||||
|
? 'Trader referred'
|
||||||
|
: 'Total traders referred'}
|
||||||
|
</p>
|
||||||
|
</Tile>
|
||||||
|
)}
|
||||||
|
<Tile className="py-3">
|
||||||
|
<h3 className="mb-1 text-2xl text-center">0.1%</h3>
|
||||||
|
<p className="text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
Maximum trader discount
|
||||||
|
</p>
|
||||||
|
</Tile>
|
||||||
|
<Tile className="py-3">
|
||||||
|
<h3 className="mb-1 text-2xl text-center">10,000</h3>
|
||||||
|
<p className="text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
Your commission (last 30d)
|
||||||
|
</p>
|
||||||
|
</Tile>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
import {
|
||||||
|
TradingAnchorButton,
|
||||||
|
VegaIcon,
|
||||||
|
VegaIconNames,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { HowItWorksTable } from './how-it-works-table';
|
||||||
|
import { LandingBanner } from './landing-banner';
|
||||||
|
import { TiersContainer } from './tiers-table';
|
||||||
|
import { BORDER_COLOR, GRADIENT } from './constants';
|
||||||
|
|
||||||
|
import { RainbowTabLink } from './buttons';
|
||||||
|
import { Outlet } from 'react-router-dom';
|
||||||
|
import { Tag } from './tag';
|
||||||
|
import { Routes } from '../../pages/client-router';
|
||||||
|
|
||||||
|
export const Referrals = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LandingBanner />
|
||||||
|
<div>
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<RainbowTabLink end to={Routes.REFERRALS}>
|
||||||
|
Your referrals
|
||||||
|
</RainbowTabLink>
|
||||||
|
<RainbowTabLink to={Routes.REFERRALS_CREATE_CODE}>
|
||||||
|
Your referrals
|
||||||
|
</RainbowTabLink>
|
||||||
|
<RainbowTabLink to={Routes.REFERRALS_APPLY_CODE}>
|
||||||
|
Apply a code
|
||||||
|
</RainbowTabLink>
|
||||||
|
</div>
|
||||||
|
<div className="py-16 border-t border-b border-vega-cdark-500">
|
||||||
|
<Outlet />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row items-baseline justify-between mt-10 mb-5">
|
||||||
|
<h2 className="text-2xl">Referral tiers</h2>
|
||||||
|
<span className="text-base">
|
||||||
|
<span className="text-vega-clight-200 dark:text-vega-cdark-200">
|
||||||
|
Program ends:
|
||||||
|
</span>{' '}
|
||||||
|
16 epochs
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="mb-20">
|
||||||
|
<TiersContainer />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-row items-baseline justify-between mb-5">
|
||||||
|
<h2 className="text-2xl">Staking multipliers</h2>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col mb-20 jjustify-items-stretch md:flex-row gap-5">
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'overflow-hidden',
|
||||||
|
'border rounded-md w-full',
|
||||||
|
BORDER_COLOR
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div aria-hidden>
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
|
src="/1x.png"
|
||||||
|
alt="1x multiplier"
|
||||||
|
width={768}
|
||||||
|
height={400}
|
||||||
|
className="w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={classNames('p-3', GRADIENT)}>
|
||||||
|
<h3 className="mb-3 text-xl">Tradestarter</h3>
|
||||||
|
<p className="text-base text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
Stake a minimum of 100 $VEGA tokens
|
||||||
|
</p>
|
||||||
|
<Tag color="green">Reward multiplier 1x</Tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'overflow-hidden',
|
||||||
|
'border rounded-md w-full',
|
||||||
|
BORDER_COLOR
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div aria-hidden>
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
|
src="/2x.png"
|
||||||
|
alt="2x multiplier"
|
||||||
|
width={768}
|
||||||
|
height={400}
|
||||||
|
className="w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={classNames('p-3', GRADIENT)}>
|
||||||
|
<h3 className="mb-3 text-xl">Mid level degen</h3>
|
||||||
|
<p className="text-base text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
Stake a minimum of 1000 $VEGA tokens
|
||||||
|
</p>
|
||||||
|
<Tag color="blue">Reward multiplier 2x</Tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'overflow-hidden',
|
||||||
|
'border rounded-md w-full',
|
||||||
|
BORDER_COLOR
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div aria-hidden>
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
|
src="/3x.png"
|
||||||
|
alt="3x multiplier"
|
||||||
|
width={768}
|
||||||
|
height={400}
|
||||||
|
className="w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={classNames('p-3', GRADIENT)}>
|
||||||
|
<h3 className="mb-3 text-xl">Reward hoarder</h3>
|
||||||
|
<p className="text-base text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
Stake a minimum of 10,000 $VEGA tokens
|
||||||
|
</p>
|
||||||
|
<Tag color="pink">Reward multiplier 3x</Tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-10 mb-5 text-center">
|
||||||
|
<h2 className="text-2xl">How it works</h2>
|
||||||
|
</div>
|
||||||
|
<div className="md:w-[60%] mx-auto">
|
||||||
|
<HowItWorksTable />
|
||||||
|
<div className="mt-5">
|
||||||
|
<TradingAnchorButton
|
||||||
|
className="mx-auto w-max"
|
||||||
|
href="https://docs.vega.xyz/"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Read the terms <VegaIcon name={VegaIconNames.OPEN_EXTERNAL} />
|
||||||
|
</TradingAnchorButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Referrals;
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import { Tooltip, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import type { HTMLAttributes } from 'react';
|
||||||
|
import { BORDER_COLOR, GRADIENT } from './constants';
|
||||||
|
|
||||||
|
type TableColumnDefinition = {
|
||||||
|
displayName?: string;
|
||||||
|
name: string;
|
||||||
|
tooltip?: string;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TableProps = {
|
||||||
|
columns: TableColumnDefinition[];
|
||||||
|
data: Record<TableColumnDefinition['name'] | 'className', React.ReactNode>[];
|
||||||
|
noHeader?: boolean;
|
||||||
|
noCollapse?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const INNER_BORDER_STYLE = `border-b ${BORDER_COLOR}`;
|
||||||
|
|
||||||
|
export const Table = ({
|
||||||
|
columns,
|
||||||
|
data,
|
||||||
|
noHeader = false,
|
||||||
|
noCollapse = false,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: TableProps & HTMLAttributes<HTMLTableElement>) => {
|
||||||
|
const header = (
|
||||||
|
<thead className={classNames({ 'max-md:hidden': !noCollapse })}>
|
||||||
|
<tr>
|
||||||
|
{columns.map(({ displayName, name, tooltip }) => (
|
||||||
|
<th
|
||||||
|
key={name}
|
||||||
|
col-id={name}
|
||||||
|
className={classNames(
|
||||||
|
'px-5 py-3 text-sm text-vega-clight-100 dark:text-vega-cdark-100',
|
||||||
|
INNER_BORDER_STYLE
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span className="flex flex-row gap-2 items-center">
|
||||||
|
<span>{displayName}</span>
|
||||||
|
{tooltip ? (
|
||||||
|
<Tooltip description={tooltip}>
|
||||||
|
<button className="text-vega-clight-400 dark:text-vega-cdark-400 no-underline decoration-transparent w-[12px] h-[12px] inline-flex">
|
||||||
|
<VegaIcon size={12} name={VegaIconNames.INFO} />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
) : null}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<table
|
||||||
|
className={classNames(
|
||||||
|
'w-full',
|
||||||
|
'border-separate border rounded-md border-spacing-0',
|
||||||
|
BORDER_COLOR,
|
||||||
|
GRADIENT,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{!noHeader && header}
|
||||||
|
<tbody>
|
||||||
|
{data.map((d, i) => (
|
||||||
|
<tr
|
||||||
|
key={i}
|
||||||
|
className={classNames(d['className'] as string, {
|
||||||
|
'max-md:flex flex-col w-full': !noCollapse,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{columns.map(({ name, displayName, className }, j) => (
|
||||||
|
<td
|
||||||
|
className={classNames(
|
||||||
|
'px-5 py-3 text-base',
|
||||||
|
{
|
||||||
|
'max-md:flex max-md:flex-col max-md:justify-between':
|
||||||
|
!noCollapse,
|
||||||
|
},
|
||||||
|
INNER_BORDER_STYLE,
|
||||||
|
{
|
||||||
|
'border-none': i === data.length - 1 && noCollapse,
|
||||||
|
'md:border-none': i === data.length - 1,
|
||||||
|
'max-md:border-none':
|
||||||
|
i === data.length - 1 && j === columns.length - 1,
|
||||||
|
},
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
key={`${i}-${name}`}
|
||||||
|
>
|
||||||
|
{/** display column name in mobile view */}
|
||||||
|
{!noCollapse &&
|
||||||
|
!noHeader &&
|
||||||
|
displayName &&
|
||||||
|
displayName.length > 0 && (
|
||||||
|
<span
|
||||||
|
aria-hidden
|
||||||
|
className="md:hidden font-mono text-xs px-0 text-vega-clight-100 dark:text-vega-cdark-100"
|
||||||
|
>
|
||||||
|
{displayName}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span>{d[name]}</span>
|
||||||
|
</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import type { HTMLAttributes } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
type TagProps = {
|
||||||
|
color?: 'yellow' | 'green' | 'blue' | 'purple' | 'pink' | 'orange' | 'none';
|
||||||
|
};
|
||||||
|
export const Tag = ({
|
||||||
|
color = 'none',
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: TagProps & HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'mt-3 w-max border rounded-[1rem] py-[0.125rem] px-2 text-xs',
|
||||||
|
{
|
||||||
|
'border-vega-yellow-500 text-vega-yellow-500': color === 'yellow',
|
||||||
|
'border-vega-green-500 text-vega-green-500': color === 'green',
|
||||||
|
'border-vega-blue-500 text-vega-blue-500': color === 'blue',
|
||||||
|
'border-vega-purple-500 text-vega-purple-500': color === 'purple',
|
||||||
|
'border-vega-pink-500 text-vega-pink-500': color === 'pink',
|
||||||
|
'border-vega-orange-500 text-vega-orange-500': color === 'orange',
|
||||||
|
'border-vega-clight-100 text-vega-clight-100 dark:border-vega-cdark-100 dark:text-vega-cdark-100':
|
||||||
|
color === 'none',
|
||||||
|
},
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { useReferralProgram } from './hooks/use-referral-program';
|
||||||
|
import { Table } from './table';
|
||||||
|
|
||||||
|
export const TiersContainer = () => {
|
||||||
|
const { benefitTiers } = useReferralProgram();
|
||||||
|
|
||||||
|
return <TiersTable data={benefitTiers} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TiersTable = ({
|
||||||
|
data,
|
||||||
|
}: {
|
||||||
|
data: Array<{
|
||||||
|
tier: number;
|
||||||
|
commission: string;
|
||||||
|
discount: string;
|
||||||
|
volume: string;
|
||||||
|
}>;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Table
|
||||||
|
columns={[
|
||||||
|
{ name: 'tier', displayName: 'Tier' },
|
||||||
|
{
|
||||||
|
name: 'commission',
|
||||||
|
displayName: 'Referrer commission',
|
||||||
|
tooltip: 'A percentage of commission earned by the referrer',
|
||||||
|
},
|
||||||
|
{ name: 'discount', displayName: 'Referrer trading discount' },
|
||||||
|
{ name: 'volume', displayName: 'Min. trading volume' },
|
||||||
|
]}
|
||||||
|
data={data.map((d) => ({
|
||||||
|
...d,
|
||||||
|
className:
|
||||||
|
'from-vega-pink-400 dark:from-vega-pink-600 to-20% bg-highlight',
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import type { HTMLAttributes } from 'react';
|
||||||
|
import { BORDER_COLOR, GRADIENT } from './constants';
|
||||||
|
|
||||||
|
type TileProps = {
|
||||||
|
variant?: 'rainbow' | 'default';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Tile = ({
|
||||||
|
variant = 'default',
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
}: TileProps & HTMLAttributes<HTMLDivElement>) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
{
|
||||||
|
'bg-rainbow p-[0.125rem]': variant === 'rainbow',
|
||||||
|
[`border-2 ${BORDER_COLOR} p-0`]: variant === 'default',
|
||||||
|
},
|
||||||
|
'rounded-lg overflow-hidden'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
{
|
||||||
|
'bg-white dark:bg-vega-cdark-900 text-black dark:text-white rounded-[0.35rem] overflow-hidden':
|
||||||
|
variant === 'rainbow',
|
||||||
|
},
|
||||||
|
'p-6',
|
||||||
|
GRADIENT,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -12,6 +12,7 @@ import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
|||||||
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||||
import { ViewType, useSidebar } from '../sidebar';
|
import { ViewType, useSidebar } from '../sidebar';
|
||||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||||
|
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||||
|
|
||||||
export const AccountsContainer = ({
|
export const AccountsContainer = ({
|
||||||
pinnedAsset,
|
pinnedAsset,
|
||||||
@@ -21,7 +22,8 @@ export const AccountsContainer = ({
|
|||||||
const onMarketClick = useMarketClickHandler(true);
|
const onMarketClick = useMarketClickHandler(true);
|
||||||
const { pubKey, isReadOnly } = useVegaWallet();
|
const { pubKey, isReadOnly } = useVegaWallet();
|
||||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||||
const setView = useSidebar((store) => store.setView);
|
const currentRouteId = useGetCurrentRouteId();
|
||||||
|
const setViews = useSidebar((store) => store.setViews);
|
||||||
|
|
||||||
const gridStore = useAccountStore((store) => store.gridStore);
|
const gridStore = useAccountStore((store) => store.gridStore);
|
||||||
const updateGridStore = useAccountStore((store) => store.updateGridStore);
|
const updateGridStore = useAccountStore((store) => store.updateGridStore);
|
||||||
@@ -49,13 +51,13 @@ export const AccountsContainer = ({
|
|||||||
partyId={pubKey}
|
partyId={pubKey}
|
||||||
onClickAsset={onClickAsset}
|
onClickAsset={onClickAsset}
|
||||||
onClickWithdraw={(assetId) => {
|
onClickWithdraw={(assetId) => {
|
||||||
setView({ type: ViewType.Withdraw, assetId });
|
setViews({ type: ViewType.Withdraw, assetId }, currentRouteId);
|
||||||
}}
|
}}
|
||||||
onClickDeposit={(assetId) => {
|
onClickDeposit={(assetId) => {
|
||||||
setView({ type: ViewType.Deposit, assetId });
|
setViews({ type: ViewType.Deposit, assetId }, currentRouteId);
|
||||||
}}
|
}}
|
||||||
onClickTransfer={(assetId) => {
|
onClickTransfer={(assetId) => {
|
||||||
setView({ type: ViewType.Transfer, assetId });
|
setViews({ type: ViewType.Transfer, assetId }, currentRouteId);
|
||||||
}}
|
}}
|
||||||
onMarketClick={onMarketClick}
|
onMarketClick={onMarketClick}
|
||||||
isReadOnly={isReadOnly}
|
isReadOnly={isReadOnly}
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||||
import { ViewType, useSidebar } from '../sidebar';
|
import { ViewType, useSidebar } from '../sidebar';
|
||||||
|
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||||
|
|
||||||
export const AccountsMenu = () => {
|
export const AccountsMenu = () => {
|
||||||
const setView = useSidebar((store) => store.setView);
|
const currentRouteId = useGetCurrentRouteId();
|
||||||
|
const setViews = useSidebar((store) => store.setViews);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TradingButton
|
<TradingButton
|
||||||
size="extra-small"
|
size="extra-small"
|
||||||
data-testid="open-transfer"
|
data-testid="open-transfer"
|
||||||
onClick={() => setView({ type: ViewType.Transfer })}
|
onClick={() => setViews({ type: ViewType.Transfer }, currentRouteId)}
|
||||||
>
|
>
|
||||||
{t('Transfer')}
|
{t('Transfer')}
|
||||||
</TradingButton>
|
</TradingButton>
|
||||||
<TradingButton
|
<TradingButton
|
||||||
size="extra-small"
|
size="extra-small"
|
||||||
onClick={() => setView({ type: ViewType.Deposit })}
|
onClick={() => setViews({ type: ViewType.Deposit }, currentRouteId)}
|
||||||
>
|
>
|
||||||
{t('Deposit')}
|
{t('Deposit')}
|
||||||
</TradingButton>
|
</TradingButton>
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
export const THROTTLE_UPDATE_TIME = 500;
|
export const THROTTLE_UPDATE_TIME = 500;
|
||||||
export const ONBOARDING_VIEWED_KEY = 'vega_onboarding_viewed';
|
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||||
import { ViewType, useSidebar } from '../sidebar';
|
import { ViewType, useSidebar } from '../sidebar';
|
||||||
|
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||||
|
|
||||||
export const DepositsMenu = () => {
|
export const DepositsMenu = () => {
|
||||||
const setView = useSidebar((store) => store.setView);
|
const currentRouteId = useGetCurrentRouteId();
|
||||||
|
const setViews = useSidebar((store) => store.setViews);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TradingButton
|
<TradingButton
|
||||||
size="extra-small"
|
size="extra-small"
|
||||||
onClick={() => setView({ type: ViewType.Deposit })}
|
onClick={() => setViews({ type: ViewType.Deposit }, currentRouteId)}
|
||||||
data-testid="deposit-button"
|
data-testid="deposit-button"
|
||||||
>
|
>
|
||||||
{t('Deposit')}
|
{t('Deposit')}
|
||||||
|
|||||||
@@ -4,16 +4,19 @@ import classNames from 'classnames';
|
|||||||
import { Routes as AppRoutes } from '../../pages/client-router';
|
import { Routes as AppRoutes } from '../../pages/client-router';
|
||||||
import { MarketHeader } from '../market-header';
|
import { MarketHeader } from '../market-header';
|
||||||
import { LiquidityHeader } from '../liquidity-header';
|
import { LiquidityHeader } from '../liquidity-header';
|
||||||
|
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||||
|
|
||||||
export const LayoutWithSidebar = () => {
|
export const LayoutWithSidebar = () => {
|
||||||
const sidebarView = useSidebar((store) => store.view);
|
const currentRouteId = useGetCurrentRouteId();
|
||||||
|
const views = useSidebar((store) => store.views);
|
||||||
|
const sidebarView = views[currentRouteId] || null;
|
||||||
const sidebarOpen = sidebarView !== null;
|
const sidebarOpen = sidebarView !== null;
|
||||||
|
|
||||||
const gridClasses = classNames(
|
const gridClasses = classNames(
|
||||||
'h-full relative z-0 grid',
|
'h-full relative z-0 grid',
|
||||||
'grid-rows-[min-content_1fr_40px]',
|
'grid-rows-[min-content_1fr_40px]',
|
||||||
'lg:grid-rows-[min-content_1fr]',
|
'lg:grid-rows-[min-content_1fr]',
|
||||||
'lg:grid-cols-[1fr_350px_40px]'
|
'lg:grid-cols-[1fr_280px_40px]',
|
||||||
|
'xxxl:grid-cols-[1fr_320px_40px]'
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const MarketSuccessorProposalBanner = ({
|
|||||||
?.successorConfiguration?.parentMarketId === marketId
|
?.successorConfiguration?.parentMarketId === marketId
|
||||||
) ?? [];
|
) ?? [];
|
||||||
const [visible, setVisible] = useState(true);
|
const [visible, setVisible] = useState(true);
|
||||||
const tokenLink = useLinks(DApp.Token);
|
const tokenLink = useLinks(DApp.Governance);
|
||||||
if (visible && successors.length) {
|
if (visible && successors.length) {
|
||||||
return (
|
return (
|
||||||
<NotificationBanner
|
<NotificationBanner
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import type { SortType } from './sort-dropdown';
|
|||||||
import { SortTypeMapping } from './sort-dropdown';
|
import { SortTypeMapping } from './sort-dropdown';
|
||||||
import { Sort } from './sort-dropdown';
|
import { Sort } from './sort-dropdown';
|
||||||
import { subDays } from 'date-fns';
|
import { subDays } from 'date-fns';
|
||||||
import { isMarketActive } from './use-market-selector-list';
|
import { isMarketActive } from '../../lib/utils';
|
||||||
|
|
||||||
jest.mock('@vegaprotocol/markets');
|
jest.mock('@vegaprotocol/markets');
|
||||||
const mockUseMarketList = useMarketList as jest.Mock;
|
const mockUseMarketList = useMarketList as jest.Mock;
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import merge from 'lodash/merge';
|
import merge from 'lodash/merge';
|
||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
import {
|
import { useMarketSelectorList } from './use-market-selector-list';
|
||||||
isMarketActive,
|
import { isMarketActive } from '../../lib/utils';
|
||||||
useMarketSelectorList,
|
import { Product } from './product-selector';
|
||||||
} from './use-market-selector-list';
|
|
||||||
import { Product } from '../../components/market-selector/product-selector';
|
|
||||||
import { Sort } from './sort-dropdown';
|
import { Sort } from './sort-dropdown';
|
||||||
import { createMarketFragment } from '@vegaprotocol/mock';
|
import { createMarketFragment } from '@vegaprotocol/mock';
|
||||||
import { MarketState } from '@vegaprotocol/types';
|
import { MarketState } from '@vegaprotocol/types';
|
||||||
import { useMarketList } from '@vegaprotocol/markets';
|
import { useMarketList } from '@vegaprotocol/markets';
|
||||||
import type { Filter } from '../../components/market-selector';
|
import type { Filter } from './market-selector';
|
||||||
import { subDays } from 'date-fns';
|
import { subDays } from 'date-fns';
|
||||||
|
|
||||||
jest.mock('@vegaprotocol/markets', () => ({
|
jest.mock('@vegaprotocol/markets', () => ({
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import orderBy from 'lodash/orderBy';
|
import orderBy from 'lodash/orderBy';
|
||||||
import { MarketState } from '@vegaprotocol/types';
|
|
||||||
import { calcTradedFactor, useMarketList } from '@vegaprotocol/markets';
|
import { calcTradedFactor, useMarketList } from '@vegaprotocol/markets';
|
||||||
import { priceChangePercentage } from '@vegaprotocol/utils';
|
import { priceChangePercentage } from '@vegaprotocol/utils';
|
||||||
import type { Filter } from '../../components/market-selector/market-selector';
|
import type { Filter } from '../../components/market-selector/market-selector';
|
||||||
import { Sort } from './sort-dropdown';
|
import { Sort } from './sort-dropdown';
|
||||||
import { Product } from './product-selector';
|
import { Product } from './product-selector';
|
||||||
|
import { isMarketActive } from '../../lib/utils';
|
||||||
// Used for sort order and filter
|
|
||||||
const MARKET_TEMPLATE = [
|
|
||||||
MarketState.STATE_ACTIVE,
|
|
||||||
MarketState.STATE_SUSPENDED,
|
|
||||||
MarketState.STATE_PENDING,
|
|
||||||
];
|
|
||||||
|
|
||||||
export const useMarketSelectorList = ({
|
export const useMarketSelectorList = ({
|
||||||
product,
|
product,
|
||||||
@@ -87,7 +80,3 @@ export const useMarketSelectorList = ({
|
|||||||
|
|
||||||
return { markets, data, loading, error, reload };
|
return { markets, data, loading, error, reload };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isMarketActive = (state: MarketState) => {
|
|
||||||
return MARKET_TEMPLATE.includes(state);
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ describe('Navbar', () => {
|
|||||||
['/markets/all', 'Markets'],
|
['/markets/all', 'Markets'],
|
||||||
[`/markets/${marketId}`, 'Trading'],
|
[`/markets/${marketId}`, 'Trading'],
|
||||||
['/portfolio', 'Portfolio'],
|
['/portfolio', 'Portfolio'],
|
||||||
|
[expect.stringContaining('governance'), 'Governance'],
|
||||||
];
|
];
|
||||||
|
|
||||||
const links = screen.getAllByRole('link');
|
const links = screen.getAllByRole('link');
|
||||||
@@ -88,6 +89,7 @@ describe('Navbar', () => {
|
|||||||
['/markets/all', 'Markets'],
|
['/markets/all', 'Markets'],
|
||||||
[`/markets/${marketId}`, 'Trading'],
|
[`/markets/${marketId}`, 'Trading'],
|
||||||
['/portfolio', 'Portfolio'],
|
['/portfolio', 'Portfolio'],
|
||||||
|
[expect.stringContaining('governance'), 'Governance'],
|
||||||
];
|
];
|
||||||
const links = menu.getAllByRole('link');
|
const links = menu.getAllByRole('link');
|
||||||
links.forEach((link, i) => {
|
links.forEach((link, i) => {
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import type { ButtonHTMLAttributes, LiHTMLAttributes, ReactNode } from 'react';
|
import type { ButtonHTMLAttributes, LiHTMLAttributes, ReactNode } from 'react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useEnvironment, DocsLinks, Networks } from '@vegaprotocol/environment';
|
import {
|
||||||
|
useEnvironment,
|
||||||
|
DocsLinks,
|
||||||
|
Networks,
|
||||||
|
DApp,
|
||||||
|
useLinks,
|
||||||
|
} from '@vegaprotocol/environment';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useGlobalStore } from '../../stores';
|
import { useGlobalStore } from '../../stores';
|
||||||
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
|
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
|
||||||
@@ -59,14 +65,14 @@ export const Navbar = ({
|
|||||||
<VLogo className="w-4" />
|
<VLogo className="w-4" />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
{/* Left section */}
|
{/* Left section */}
|
||||||
<div className="lg:hidden flex items-center">{children}</div>
|
<div className="flex items-center lg:hidden">{children}</div>
|
||||||
{/* Used to show header in nav on mobile */}
|
{/* Used to show header in nav on mobile */}
|
||||||
<div className="hidden lg:block">
|
<div className="hidden lg:block">
|
||||||
<NavbarMenu onClick={() => setMenu(null)} />
|
<NavbarMenu onClick={() => setMenu(null)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right section */}
|
{/* Right section */}
|
||||||
<div className="ml-auto flex justify-end items-center gap-2">
|
<div className="flex items-center justify-end ml-auto gap-2">
|
||||||
<ProtocolUpgradeCountdown />
|
<ProtocolUpgradeCountdown />
|
||||||
<NavbarMobileButton
|
<NavbarMobileButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -100,7 +106,7 @@ export const Navbar = ({
|
|||||||
onOpenChange={(open) => setMenu((x) => (open ? x : null))}
|
onOpenChange={(open) => setMenu((x) => (open ? x : null))}
|
||||||
>
|
>
|
||||||
<D.Overlay
|
<D.Overlay
|
||||||
className="lg:hidden fixed inset-0 dark:bg-black/80 bg-black/50 z-20"
|
className="fixed inset-0 z-20 lg:hidden dark:bg-black/80 bg-black/50"
|
||||||
data-testid="navbar-menu-overlay"
|
data-testid="navbar-menu-overlay"
|
||||||
/>
|
/>
|
||||||
<D.Content
|
<D.Content
|
||||||
@@ -111,7 +117,7 @@ export const Navbar = ({
|
|||||||
)}
|
)}
|
||||||
data-testid="navbar-menu-content"
|
data-testid="navbar-menu-content"
|
||||||
>
|
>
|
||||||
<div className="flex justify-end items-center h-10 p-1">
|
<div className="flex items-center justify-end h-10 p-1">
|
||||||
<NavbarMobileButton onClick={() => setMenu(null)}>
|
<NavbarMobileButton onClick={() => setMenu(null)}>
|
||||||
<span className="sr-only">{t('Close menu')}</span>
|
<span className="sr-only">{t('Close menu')}</span>
|
||||||
<VegaIcon name={VegaIconNames.CROSS} size={24} />
|
<VegaIcon name={VegaIconNames.CROSS} size={24} />
|
||||||
@@ -174,11 +180,21 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
|
|||||||
{t('Trading')}
|
{t('Trading')}
|
||||||
</NavbarLink>
|
</NavbarLink>
|
||||||
</NavbarItem>
|
</NavbarItem>
|
||||||
|
<NavbarItem>
|
||||||
|
<NavbarLink to={Links[Routes.REFERRALS]()} onClick={onClick}>
|
||||||
|
{t('Referrals')}
|
||||||
|
</NavbarLink>
|
||||||
|
</NavbarItem>
|
||||||
<NavbarItem>
|
<NavbarItem>
|
||||||
<NavbarLink to={Links[Routes.PORTFOLIO]()} onClick={onClick}>
|
<NavbarLink to={Links[Routes.PORTFOLIO]()} onClick={onClick}>
|
||||||
{t('Portfolio')}
|
{t('Portfolio')}
|
||||||
</NavbarLink>
|
</NavbarLink>
|
||||||
</NavbarItem>
|
</NavbarItem>
|
||||||
|
<NavbarItem>
|
||||||
|
<NavbarLinkExternal to={useLinks(DApp.Governance)()}>
|
||||||
|
{t('Governance')}
|
||||||
|
</NavbarLinkExternal>
|
||||||
|
</NavbarItem>
|
||||||
<NavbarItem>
|
<NavbarItem>
|
||||||
<NavbarTrigger>{t('Resources')}</NavbarTrigger>
|
<NavbarTrigger>{t('Resources')}</NavbarTrigger>
|
||||||
<NavbarContent data-testid="navbar-content-resources">
|
<NavbarContent data-testid="navbar-content-resources">
|
||||||
@@ -336,7 +352,7 @@ const NavbarLinkExternal = ({
|
|||||||
<NavLink
|
<NavLink
|
||||||
to={to}
|
to={to}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'flex lg:inline-flex gap-2 justify-between items-center relative',
|
'flex gap-2 lg:h-full items-center',
|
||||||
'px-6 py-2 lg:p-0 text-lg lg:text-sm',
|
'px-6 py-2 lg:p-0 text-lg lg:text-sm',
|
||||||
'hover:text-vega-clight-100 dark:hover:text-vega-cdark-100'
|
'hover:text-vega-clight-100 dark:hover:text-vega-cdark-100'
|
||||||
)}
|
)}
|
||||||
@@ -344,7 +360,7 @@ const NavbarLinkExternal = ({
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<span>{children}</span>
|
<span>{children}</span>
|
||||||
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} />
|
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={14} />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</N.Link>
|
</N.Link>
|
||||||
);
|
);
|
||||||
@@ -364,8 +380,8 @@ const BurgerIcon = () => (
|
|||||||
|
|
||||||
const NavbarListDivider = () => {
|
const NavbarListDivider = () => {
|
||||||
return (
|
return (
|
||||||
<div className="py-2 px-6 lg:px-0" role="separator">
|
<div className="px-6 py-2 lg:px-0" role="separator">
|
||||||
<div className="h-px lg:h-full w-full lg:w-px bg-vega-clight-500 dark:bg-vega-cdark-500" />
|
<div className="w-full h-px lg:h-full lg:w-px bg-vega-clight-500 dark:bg-vega-cdark-500" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import { OrderbookManager } from '@vegaprotocol/market-depth';
|
import { OrderbookManager } from '@vegaprotocol/market-depth';
|
||||||
import { ViewType, useSidebar } from '../sidebar';
|
import { ViewType, useSidebar } from '../sidebar';
|
||||||
import { useDealTicketFormValues } from '@vegaprotocol/deal-ticket';
|
import { useDealTicketFormValues } from '@vegaprotocol/deal-ticket';
|
||||||
|
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||||
|
|
||||||
export const OrderbookContainer = ({ marketId }: { marketId: string }) => {
|
export const OrderbookContainer = ({ marketId }: { marketId: string }) => {
|
||||||
|
const currentRouteId = useGetCurrentRouteId();
|
||||||
const update = useDealTicketFormValues((state) => state.updateAll);
|
const update = useDealTicketFormValues((state) => state.updateAll);
|
||||||
const setView = useSidebar((store) => store.setView);
|
const setViews = useSidebar((store) => store.setViews);
|
||||||
return (
|
return (
|
||||||
<OrderbookManager
|
<OrderbookManager
|
||||||
marketId={marketId}
|
marketId={marketId}
|
||||||
onClick={(values) => {
|
onClick={(values) => {
|
||||||
update(marketId, values);
|
update(marketId, values);
|
||||||
setView({ type: ViewType.Order });
|
setViews({ type: ViewType.Order }, currentRouteId);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user