Compare commits

..
Author SHA1 Message Date
Matthew Russell 917c452116 refactor: use zustand for theme store 2022-09-28 15:54:14 -07:00
Matthew Russell 166c9b6fb9 fix: hydration error due to theme switcher 2022-09-28 15:53:22 -07:00
1409 changed files with 33942 additions and 71000 deletions
@@ -1,28 +0,0 @@
inputs:
all:
description: 'Install all binaries'
default: false
version:
description: 'Vega version'
gobin:
description: 'GOBIN path'
default: '/home/runner/go/bin'
runs:
using: 'composite'
steps:
- name: Install Vega binaries
shell: bash
run: |
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ inputs.version }}/vega-linux-amd64.zip' -q
unzip vega-linux-amd64.zip -d ${{ inputs.gobin }}
- name: Checkout vegawallet-dummy
uses: actions/checkout@v3
with:
repository: 'vegaprotocol/vegawallet-dummy'
path: './dummy'
- name: Install vegawallet-dummy binaries
shell: bash
run: go install
working-directory: ./dummy
@@ -1,30 +0,0 @@
inputs:
github-token:
description: 'github token'
runs:
using: 'composite'
steps:
- name: Checkout capsule
uses: actions/checkout@v2
with:
repository: vegaprotocol/vegacapsule
ref: main
token: ${{ inputs.github-token }}
path: './capsule'
- name: Build capsule
run: go install
shell: bash
working-directory: capsule
- name: Login to docker
shell: bash
run: echo -n ${{ inputs.github-token }} | docker login https://ghcr.io -u vega-ci-bot --password-stdin
- name: Start nomad
shell: bash
run: vegacapsule nomad &
- name: Bootstrap network
shell: bash
run: vegacapsule network bootstrap --config-path=./frontend-monorepo/vegacapsule/config.hcl --force
@@ -1,25 +0,0 @@
inputs:
passphrase:
description: 'Wallet password'
runs:
using: 'composite'
steps:
- name: Create passphrase
shell: bash
run: echo "${{ inputs.passphrase }}" > ./passphrase
- name: Initialize wallet
shell: bash
run: vega wallet init -f --home ~/.vegacapsule/testnet/wallet
- name: Import wallet
shell: bash
run: vega wallet import -w capsule_wallet --recovery-phrase-file ./frontend-monorepo/vegacapsule/recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
- name: Import network
shell: bash
run: vega wallet network import --force --from-file ./frontend-monorepo/vegacapsule/wallet-config.toml --home ~/.vegacapsule/testnet/wallet
- name: Start service using capsule network
shell: bash
run: vegawallet-dummy service run --network DV --wallet capsule_wallet --passphrase-file ./passphrase --home ~/.vegacapsule/testnet/wallet &
@@ -1,35 +0,0 @@
inputs:
recovery:
description: 'Recovery phrase'
passphrase:
description: 'Wallet password'
runs:
using: 'composite'
steps:
- name: Create passphrase
shell: bash
run: echo "${{ inputs.passphrase }}" > ./passphrase
- name: Create recovery
shell: bash
run: echo "${{ inputs.recovery }}" > ./recovery
- name: Initialize wallet
shell: bash
run: vega wallet init -f --home ~/.vegacapsule/testnet/wallet
- name: Import wallet
shell: bash
run: vega wallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
- name: Create public key 2
shell: bash
run: vega wallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
- name: Import network
shell: bash
run: vega wallet network import --from-url="https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml" --force --home ~/.vegacapsule/testnet/wallet
- name: Start service using stagnet3 network
shell: bash
run: vegawallet-dummy service run --network stagnet3 --wallet UI_Trading_Test --passphrase-file ./passphrase --home ~/.vegacapsule/testnet/wallet &
+11 -13
View File
@@ -1,27 +1,25 @@
---
name: 'Add Issues To Project Board'
name: Auto Assign Issue to New Project
'on':
issues:
types:
- opened
env:
GH_TOKEN: ${{ secrets.GH_NEW_CARD_TO_PROJECT }}
PROJECT_ID: ${{ secrets.FRONT_END_PROJECT_ID }}
ISSUE_ID: ${{ github.event.issue.node_id }}
USER: ${{ github.actor }}
types: [opened]
jobs:
add_issue:
runs-on: ubuntu-latest
steps:
- name: 'Add issue to project board'
- name: Add Issue to New Front End Project Board
env:
GITHUB_TOKEN: ${{ secrets.GH_NEW_CARD_TO_PROJECT }}
PROJECT_ID: ${{ secrets.FRONT_END_PROJECT_ID }}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
gh api graphql -f query='
mutation($user:String!, $project:ID!, $issue:ID!) {
addProjectV2ItemById(input: {clientMutationId: $user, projectId: $project, contentId: $issue}) {
item {
mutation($project:ID!, $issue:ID!) {
addProjectNextItem(input: {projectId: $project, contentId: $issue}) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f issue=$ISSUE_ID -f user=$USER
}' -f project=$PROJECT_ID -f issue=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id'
@@ -1,4 +1,4 @@
name: Cypress tests -- manual trigger
name: Capsule tests -- manual trigger
# This workflow runs the frontend tests against chosen branch
@@ -10,51 +10,196 @@ on:
required: true
type: choice
options:
- console-lite-e2e
- explorer-e2e
- liquidity-provision-dashboard-e2e
- console-lite-e2e
- stats-e2e
- token-e2e
- trading-e2e
tags:
description: 'Test tags to run'
runAlltests:
description: 'Run only smoke tests?'
required: true
type: string
default: '@smoke, @regression, @slow'
skip-nx-cache:
description: 'Add --skip-nx-cache to cypress test'
required: false
type: boolean
default: false
env:
GOBIN: /home/runner/go/bin
VEGA_VERSION: 'v0.62.1'
jobs:
manual:
name: Run Cypress tests -- manual trigger
runs-on: ubuntu-latest
name: Run capsule tests -- manual trigger
runs-on: self-hosted
env:
GO111MODULE: 'on'
VEGA_VERSION: 'v0.57.0'
steps:
- name: Set tags
run: echo TAGS="--env.grepTags '[ ${{ github.event.inputs.tags }} ]'" >> $GITHUB_ENV
#######
## Setup langs
#######
- name: Set up Go
uses: actions/setup-go@v3
id: go
with:
go-version: 1.19
- name: Set up Node 16
uses: actions/setup-node@v2
id: npm
with:
node-version: 16
- name: Set --skip-nx-cache flag
if: ${{ github.event.inputs.skip-nx-cache == 'true' }}
run: echo SKIP_NX_CACHE="--skip-nx-cache" >> $GITHUB_ENV
#######
## Install Yarn
#######
- name: Setup yarn
run: npm install -g yarn
outputs:
vega-version: ${{env.VEGA_VERSION}}
gobin: ${{env.GOBIN}}
skip-cache: ${{env.SKIP_NX_CACHE}}
tags: ${{env.TAGS}}
#######
## Checkout repos
#######
dispatch:
needs: manual
uses: ./.github/workflows/tests-dispatcher.yml
secrets: inherit
with:
project: ${{ inputs.project }}
vega-version: ${{needs.manual.outputs.vega-version}}
gobin: ${{needs.manual.outputs.gobin}}
skip-cache: ${{needs.manual.outputs.skip-cache}}
tags: ${{needs.manual.outputs.tags}}
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
path: './frontend-monorepo'
# See if we capsule is needed for this project
- name: See if capsule is necessary
if: ${{ github.event.inputs.project == 'explorer-e2e' || github.event.inputs.project == 'token-e2e' }}
run: echo RUN_CAPSULE=true >> $GITHUB_ENV
# Checkout capsule to build local network
- name: Checkout capsule
if: ${{ env.RUN_CAPSULE }}
uses: actions/checkout@v2
with:
repository: vegaprotocol/vegacapsule
ref: main
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
path: './capsule'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
#######
## Build binaries
#######
- name: Build capsule
if: ${{ env.RUN_CAPSULE }}
run: go install
working-directory: capsule
- name: Set GOBIN
run: echo GOBIN=$(go env GOPATH)/bin >> $GITHUB_ENV
- name: Install Vega binaries
if: ${{ env.RUN_CAPSULE }}
run: |
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/vega-linux-amd64.zip'
unzip vega-linux-amd64.zip -d ${{ env.GOBIN }}
- name: Install date-node binaries
if: ${{ env.RUN_CAPSULE }}
run: |
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/data-node-linux-amd64.zip'
unzip data-node-linux-amd64.zip -d ${{ env.GOBIN }}
- name: Install Vega wallet binaries
run: |
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/vegawallet-linux-amd64.zip'
unzip vegawallet-linux-amd64.zip -d ${{ env.GOBIN }}
######
## Start capsule
######
- name: Login to docker
if: ${{ env.RUN_CAPSULE }}
run: echo -n ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} | docker login https://ghcr.io -u vega-ci-bot --password-stdin
- name: Start nomad
if: ${{ env.RUN_CAPSULE }}
run: vegacapsule nomad &
- name: Bootstrap network
if: ${{ env.RUN_CAPSULE }}
run: vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl --force
working-directory: capsule
######
## Setup a Vega wallet for our user
######
- name: Create passphrase
run: echo "${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}" > ./passphrase
- name: Create recovery
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
- name: Initialize wallet
run: vegawallet init -f --home ~/.vegacapsule/testnet/wallet
- name: Import wallet
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
- name: Create public key 2
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
- name: Import fairground network
if: ${{ env.RUN_CAPSULE==false }}
run: vegawallet network import --from-url="https://raw.githubusercontent.com/vegaprotocol/networks/master/fairground/fairground.toml" --force --home ~/.vegacapsule/testnet/wallet
- name: Start service using fairground network
if: ${{ env.RUN_CAPSULE==false }}
run: vegawallet service run --network fairground --automatic-consent --home ~/.vegacapsule/testnet/wallet &
- name: Start service using capsule network
if: ${{ env.RUN_CAPSULE }}
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
######
## Run some tests
######
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run smoke Cypress tests
if: ${{ github.event.inputs.runAlltests == 'true' }}
run: yarn nx run ${{ github.event.inputs.project }}:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --env.grepTags='@smoke' --browser chrome
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPESS_ETH_WALLET_MNEMONIC }}
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: true
- name: Run Cypress tests
if: ${{ github.event.inputs.runAlltests == 'false' }}
run: yarn nx run ${{ github.event.inputs.project }}:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPESS_ETH_WALLET_MNEMONIC }}
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: true
######
## Upload logs
######
- name: Logs
if: ${{ env.RUN_CAPSULE }}
run: vegacapsule network logs > vega-capsule-logs.txt
- uses: actions/upload-artifact@v2
if: ${{ env.RUN_CAPSULE }}
with:
name: logs
path: ./vega-capsule-logs.txt
+147 -10
View File
@@ -1,19 +1,156 @@
name: Cypress tests -- night run
name: Capsule tests -- night run
# This workflow runs the frontend tests against latest develop of the core to preempt breaking changes
on:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:
jobs:
nightly:
uses: ./.github/workflows/tests-dispatcher.yml
secrets: inherit
with:
project: '[console-lite-e2e, explorer-e2e, liquidity-provision-dashboard-e2e, stats-e2e, token-e2e, trading-e2e]'
vega-version: 'v0.62.1'
gobin: /home/runner/go/bin
tags: --env.grepTags '[ @smoke, @regression, @slow ]'
night-run: true
name: Run capsule tests -- nightly
runs-on: self-hosted
env:
GO111MODULE: 'on'
VEGA_VERSION: 'v0.57.0'
steps:
#######
## Setup langs
#######
- name: Set up Go
uses: actions/setup-go@v3
id: go
with:
go-version: 1.19
- name: Set up Node 16
uses: actions/setup-node@v2
id: npm
with:
node-version: 16
#######
## Install Yarn
#######
- name: Setup yarn
run: npm install -g yarn
#######
## Checkout repos
#######
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
path: './frontend-monorepo'
# Checkout capsule to build local network
- name: Checkout capsule
uses: actions/checkout@v2
with:
repository: vegaprotocol/vegacapsule
ref: main
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
path: './capsule'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
#######
## Build binaries
#######
- name: Build capsule
run: go install
working-directory: capsule
- name: Set GOBIN
run: echo GOBIN=$(go env GOPATH)/bin >> $GITHUB_ENV
- name: Install Vega binaries
run: |
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/vega-linux-amd64.zip'
unzip vega-linux-amd64.zip -d ${{ env.GOBIN }}
- name: Install date-node binaries
run: |
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/data-node-linux-amd64.zip'
unzip data-node-linux-amd64.zip -d ${{ env.GOBIN }}
- name: Install Vega wallet binaries
run: |
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/vegawallet-linux-amd64.zip'
unzip vegawallet-linux-amd64.zip -d ${{ env.GOBIN }}
######
## Start capsule
######
- name: Login to docker
run: echo -n ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} | docker login https://ghcr.io -u vega-ci-bot --password-stdin
- name: Start nomad
run: vegacapsule nomad &
- name: Bootstrap network
run: vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl --force
working-directory: capsule
######
## Setup a Vega wallet for our user
######
- name: Create passphrase
run: echo "${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}" > ./passphrase
- name: Create recovery
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
- name: Initialize wallet
run: vegawallet init -f --home ~/.vegacapsule/testnet/wallet
- name: Import wallet
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
- name: Create public key 2
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
- name: Start service
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
######
## Run some tests
######
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: yarn nx run-many --target=e2e --all --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPESS_ETH_WALLET_MNEMONIC }}
CYPRESS_NIGHTLY_RUN: true
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: true
######
## Upload logs
######
- name: Logs
run: vegacapsule network logs > vega-capsule-logs.txt
- uses: actions/upload-artifact@v2
with:
name: logs
path: ./vega-capsule-logs.txt
+150 -25
View File
@@ -1,4 +1,4 @@
name: Cypress tests - PR
name: Capsule tests
on:
push:
@@ -12,18 +12,43 @@ on:
- synchronize
- ready_for_review
env:
GOBIN: /home/runner/go/bin
VEGA_VERSION: 'v0.62.1'
jobs:
pr:
runs-on: ubuntu-latest
name: Run capsule tests - PR
runs-on: self-hosted
env:
GO111MODULE: 'on'
VEGA_VERSION: 'v0.57.0'
steps:
#######
## Setup langs
#######
- name: Set up Go
uses: actions/setup-go@v3
id: go
with:
go-version: 1.19
- name: Set up Node 16
uses: actions/setup-node@v2
id: npm
with:
node-version: 16
#######
## Install Yarn
#######
- name: Setup yarn
run: npm install -g yarn
#######
## Checkout repos
#######
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
path: './frontend-monorepo'
@@ -41,30 +66,130 @@ jobs:
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
# Check SHAs
# See affected apps to see if building all binaries is necessary
- name: See affected apps
run: echo AFFECTED=$(yarn nx print-affected --base=origin/${{github.base_ref}} --head=${{github.head_ref}} --select=projects) >> $GITHUB_ENV
working-directory: frontend-monorepo
- name: See if capsule is necessary
if: ${{ contains(env.AFFECTED, 'token') || contains(env.AFFECTED, 'token-e2e') || contains(env.AFFECTED, 'explorer') || contains(env.AFFECTED, 'explorer-e2e') }}
run: echo RUN_CAPSULE=true >> $GITHUB_ENV
# Checkout capsule to build local network
- name: Checkout capsule
if: ${{ env.RUN_CAPSULE }}
uses: actions/checkout@v2
with:
repository: vegaprotocol/vegacapsule
ref: main
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
path: './capsule'
#######
## Build binaries
#######
- name: Build capsule
if: ${{ env.RUN_CAPSULE }}
run: go install
working-directory: capsule
- name: Set GOBIN
run: echo GOBIN=$(go env GOPATH)/bin >> $GITHUB_ENV
- name: Install Vega binaries
if: ${{ env.RUN_CAPSULE }}
run: |
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/vega-linux-amd64.zip'
unzip vega-linux-amd64.zip -d ${{ env.GOBIN }}
- name: Install date-node binaries
if: ${{ env.RUN_CAPSULE }}
run: |
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/data-node-linux-amd64.zip'
unzip data-node-linux-amd64.zip -d ${{ env.GOBIN }}
- name: Install Vega wallet binaries
run: |
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/vegawallet-linux-amd64.zip'
unzip vegawallet-linux-amd64.zip -d ${{ env.GOBIN }}
######
## Start capsule
######
- name: Login to docker
if: ${{ env.RUN_CAPSULE }}
run: echo -n ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} | docker login https://ghcr.io -u vega-ci-bot --password-stdin
- name: Start nomad
if: ${{ env.RUN_CAPSULE }}
run: vegacapsule nomad &
- name: Bootstrap network
if: ${{ env.RUN_CAPSULE }}
run: vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl --force
working-directory: capsule
######
## Setup a Vega wallet for our user
######
- name: Create passphrase
run: echo "${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}" > ./passphrase
- name: Create recovery
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
- name: Initialize wallet
run: vegawallet init -f --home ~/.vegacapsule/testnet/wallet
- name: Import wallet
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
- name: Create public key 2
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
- name: Import fairground network
if: ${{ env.RUN_CAPSULE==false }}
run: vegawallet network import --from-url="https://raw.githubusercontent.com/vegaprotocol/networks/master/fairground/fairground.toml" --force --home ~/.vegacapsule/testnet/wallet
- name: Start service using fairground network
if: ${{ env.RUN_CAPSULE==false }}
run: vegawallet service run --network fairground --automatic-consent --home ~/.vegacapsule/testnet/wallet &
- name: Start service using capsule network
if: ${{ env.RUN_CAPSULE }}
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
######
## Run some tests
######
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v2
with:
working-directory: frontend-monorepo
main-branch-name: ${{ github.base_ref || github.ref_name }}
set-environment-variables-for-job: true
main-branch-name: ${{github.base_ref}}
# See affected projects
- name: See affected apps
run: echo AFFECTED=$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects) >> $GITHUB_ENV
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
outputs:
projects: ${{ env.AFFECTED }}
vega-version: ${{ env.VEGA_VERSION }}
gobin: ${{ env.GOBIN }}
- name: Run Cypress tests
run: npx nx affected:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --env.grepTags='@smoke' --browser chrome
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPESS_ETH_WALLET_MNEMONIC }}
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: true
dispatch:
needs: pr
uses: ./.github/workflows/tests-dispatcher.yml
secrets: inherit
with:
project: ${{ needs.pr.outputs.projects }}
vega-version: ${{needs.pr.outputs.vega-version}}
gobin: ${{needs.pr.outputs.gobin}}
tags: "--env.grepTags='@smoke'"
######
## Upload logs
######
- name: Logs
if: ${{ env.RUN_CAPSULE }}
run: vegacapsule network logs > vega-capsule-logs.txt
- uses: actions/upload-artifact@v2
if: ${{ env.RUN_CAPSULE }}
with:
name: logs
path: ./vega-capsule-logs.txt
@@ -1,85 +0,0 @@
name: Cypress - console-lite
on:
workflow_call:
inputs:
trigger:
required: true
type: string
default: 'false'
vega-version:
required: true
type: string
gobin:
required: false
type: string
default: /home/runner/go/bin
skip-cache:
required: false
type: string
tags:
required: false
type: string
jobs:
console-lite-e2e:
if: ${{ inputs.trigger == 'true' }}
runs-on: self-hosted
steps:
# Add GOBIN to PATH
- name: Add GOBIN to PATH
run: echo ${{ inputs.gobin }} >> $GITHUB_PATH
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
#######
## Build and run Vegacapsule network
#######
- name: Install Vega binaries
uses: ./frontend-monorepo/.github/actions/install-vega-binaries
with:
version: ${{ inputs.vega-version }}
gobin: ${{ inputs.gobin }}
######
## Setup a Vega wallet for our user
######
- name: Set up Vegawallet
uses: ./frontend-monorepo/.github/actions/setup-vegawallet
with:
recovery: ${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}
passphrase: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run console-lite-e2e:e2e ${{ inputs.skip-cache }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome ${{ inputs.tags }}
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
-111
View File
@@ -1,111 +0,0 @@
name: Cypress - explorer
on:
workflow_call:
inputs:
trigger:
required: true
type: string
default: 'false'
vega-version:
required: true
type: string
gobin:
required: false
type: string
default: /home/runner/go/bin
skip-cache:
required: false
type: string
tags:
required: false
type: string
night-run:
required: false
type: boolean
default: false
jobs:
explorer-e2e:
if: ${{ inputs.trigger == 'true' }}
runs-on: self-hosted
timeout-minutes: 30
steps:
# Add GOBIN to PATH
- name: Add GOBIN to PATH
run: echo ${{ inputs.gobin }} >> $GITHUB_PATH
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
#######
## Build and run Vegacapsule network
#######
- name: Install Vega binaries
uses: ./frontend-monorepo/.github/actions/install-vega-binaries
with:
version: ${{ inputs.vega-version }}
gobin: ${{ inputs.gobin }}
- name: Build and run Vegacapsule network
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
with:
github-token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
######
## Setup a Vega wallet for our user
######
- name: Set up Vegawallet for docker
uses: ./frontend-monorepo/.github/actions/setup-vegawallet-docker
with:
passphrase: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
######
## Run some tests
######
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run explorer-e2e:e2e ${{ inputs.skip-cache }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome ${{ inputs.tags }}
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
CYPRESS_NIGHTLY_RUN: ${{ inputs.night-run }}
######
## Upload logs
######
- name: Logs
run: vegacapsule network logs > vega-capsule-logs.txt
- uses: actions/upload-artifact@v2
with:
name: logs
path: ./vega-capsule-logs.txt
@@ -1,47 +0,0 @@
name: Cypress - liquidity provision dashboard
on:
workflow_call:
inputs:
trigger:
required: true
type: string
default: 'false'
jobs:
liquidity-provision-dashboard-e2e:
timeout-minutes: 10
if: ${{ inputs.trigger == 'true' }}
runs-on: self-hosted
steps:
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run liquidity-provision-dashboard-e2e:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
working-directory: frontend-monorepo
env:
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
-31
View File
@@ -1,31 +0,0 @@
name: Cypress Console tests -- live environment
# This workflow runs using provided url
on:
workflow_dispatch:
inputs:
url:
description: 'Url'
required: true
type: string
jobs:
cypress-run:
name: Run Cypress Trading tests -- live environment
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run Cypress tests
uses: cypress-io/github-action@v4
with:
browser: chrome
record: true
project: ./apps/trading-e2e
config: baseUrl=${{ github.event.inputs.url }}
env: grepTags=@live
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-47
View File
@@ -1,47 +0,0 @@
name: Cypress - stats
on:
workflow_call:
inputs:
trigger:
required: true
type: string
default: 'false'
jobs:
stats-e2e:
runs-on: self-hosted
if: ${{ inputs.trigger == 'true' }}
timeout-minutes: 10
steps:
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run stats-e2e:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
working-directory: frontend-monorepo
env:
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
-106
View File
@@ -1,106 +0,0 @@
name: Cypress - token
on:
workflow_call:
inputs:
trigger:
required: true
type: string
default: 'false'
vega-version:
required: true
type: string
gobin:
required: false
type: string
default: /home/runner/go/bin
skip-cache:
required: false
type: string
tags:
required: false
type: string
jobs:
token-e2e:
if: ${{ inputs.trigger == 'true' }}
runs-on: self-hosted
timeout-minutes: 60
steps:
# Add GOBIN to PATH
- name: Add GOBIN to PATH
run: echo ${{ inputs.gobin }} >> $GITHUB_PATH
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
#######
## Build and run Vegacapsule network
#######
- name: Install Vega binaries
uses: ./frontend-monorepo/.github/actions/install-vega-binaries
with:
version: ${{ inputs.vega-version }}
gobin: ${{ inputs.gobin }}
- name: Build and run Vegacapsule network
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
with:
github-token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
######
## Setup a Vega wallet for our user
######
- name: Set up Vegawallet for docker
uses: ./frontend-monorepo/.github/actions/setup-vegawallet-docker
with:
passphrase: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
######
## Run some tests
######
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run token-e2e:e2e ${{ inputs.skip-cache }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome ${{ inputs.tags }}
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
######
## Upload logs
######
- name: Logs
run: vegacapsule network logs > vega-capsule-logs.txt
- uses: actions/upload-artifact@v2
with:
name: logs
path: ./vega-capsule-logs.txt
-86
View File
@@ -1,86 +0,0 @@
name: Cypress - trading
on:
workflow_call:
inputs:
trigger:
required: true
type: string
default: 'false'
vega-version:
required: true
type: string
gobin:
required: false
type: string
default: /home/runner/go/bin
skip-cache:
required: false
type: string
tags:
required: false
type: string
jobs:
trading-e2e:
if: ${{ inputs.trigger == 'true' }}
timeout-minutes: 30
runs-on: self-hosted
steps:
# Add GOBIN to PATH
- name: Add GOBIN to PATH
run: echo ${{ inputs.gobin }} >> $GITHUB_PATH
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
#######
## Build and run Vegacapsule network
#######
- name: Install Vega binaries
uses: ./frontend-monorepo/.github/actions/install-vega-binaries
with:
version: ${{ inputs.vega-version }}
gobin: ${{ inputs.gobin }}
######
## Setup a Vega wallet for our user
######
- name: Set up Vegawallet
uses: ./frontend-monorepo/.github/actions/setup-vegawallet
with:
recovery: ${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}
passphrase: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run trading-e2e:e2e ${{ inputs.skip-cache }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome ${{ inputs.tags }}
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
+1 -1
View File
@@ -3,7 +3,7 @@ name: Generate queries
on:
push:
branches:
- develop
- master
jobs:
master:
-21
View File
@@ -1,21 +0,0 @@
---
name: Verify PR title
on:
pull_request:
types: [opened, ready_for_review, reopened, edited, synchronize]
jobs:
lint_pr:
runs-on: ubuntu-latest
steps:
- name: Use Node.js 16
id: Node
uses: actions/setup-node@v2
with:
node-version: 16.14.0
- name: Install commitlint cli and config
run: npm install @commitlint/cli @commitlint/config-conventional
- name: Create config
run: echo "module.exports = {extends:['@commitlint/config-conventional']};" > commitlint.config.js
- name: Check PR title
run: echo "${{ github.event.pull_request.title }}" | npx commitlint
-2
View File
@@ -42,5 +42,3 @@ jobs:
run: yarn nx affected:test
- name: Build affected
run: yarn nx affected:build
- name: Build affected spec
run: yarn nx affected --target=build-spec
-76
View File
@@ -1,76 +0,0 @@
on:
workflow_call:
inputs:
project:
required: true
type: string
vega-version:
required: true
type: string
gobin:
required: false
type: string
default: /home/runner/go/bin
skip-cache:
required: false
type: string
tags:
required: false
type: string
night-run:
required: false
type: boolean
jobs:
run-console-lite-e2e:
uses: ./.github/workflows/cypress-console-lite-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'console-lite-e2e') || contains(inputs.project, 'console-lite') }}
vega-version: ${{ inputs.vega-version }}
gobin: ${{ inputs.gobin }}
skip-cache: ${{ inputs.skip-cache }}
tags: ${{ inputs.tags }}
run-explorer-e2e:
uses: ./.github/workflows/cypress-explorer-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'explorer-e2e') || contains(inputs.project, 'explorer') }}
vega-version: ${{ inputs.vega-version }}
gobin: ${{ inputs.gobin }}
skip-cache: ${{ inputs.skip-cache }}
tags: ${{ inputs.tags }}
night-run: ${{ inputs.night-run }}
run-liquidity-e2e:
uses: ./.github/workflows/cypress-liquidity-provision-dashboard-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'liquidity-provision-dashboard-e2e') || contains(inputs.project, 'liquidity-provision-dashboard') }}
run-stats-e2e:
uses: ./.github/workflows/cypress-stats-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'stats-e2e') || contains(inputs.project, 'stats') }}
run-token-e2e:
uses: ./.github/workflows/cypress-token-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'token-e2e') || contains(inputs.project, 'token') }}
vega-version: ${{ inputs.vega-version }}
gobin: ${{ inputs.gobin }}
skip-cache: ${{ inputs.skip-cache }}
tags: ${{ inputs.tags }}
run-trading-e2e:
uses: ./.github/workflows/cypress-trading-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'trading-e2e') || contains(inputs.project, 'trading') }}
vega-version: ${{ inputs.vega-version }}
gobin: ${{ inputs.gobin }}
skip-cache: ${{ inputs.skip-cache }}
tags: ${{ inputs.tags }}
+1 -19
View File
@@ -1,24 +1,6 @@
module.exports = {
stories: [],
addons: [
'@storybook/addon-actions',
'@storybook/addon-viewport',
{
name: '@storybook/addon-docs',
options: {
configureJSX: true,
babelOptions: {},
sourceLoaderOptions: null,
transcludeMarkdown: true,
},
},
'@storybook/addon-controls',
'@storybook/addon-backgrounds',
'@storybook/addon-toolbars',
'@storybook/addon-measure',
'@storybook/addon-outline',
'@storybook/addon-a11y',
],
addons: ['@storybook/addon-essentials', '@storybook/addon-a11y'],
// uncomment the property below if you want to apply some webpack config globally
// webpackFinal: async (config, { configType }) => {
// // Make whatever fine-grained changes you need that should apply to all storybook configs
Vendored
-20
View File
@@ -1,20 +0,0 @@
@Library('vega-shared-library') _
def commitHash = 'UNKNOWN'
pipeline {
agent any
options {
skipDefaultCheckout true
parallelsAlwaysFailFast()
}
stages {
stage('approbation') {
steps {
sh 'printenv'
checkout scm
runApprobation ignoreFailure: false, frontendBranch: env.BRANCH_NAME, type: 'frontend'
}
}
}
}
+1 -6
View File
@@ -30,10 +30,6 @@ An application for the status of the Vega network. Showing block height and othe
Hosting for static content being shared across apps, for example fonts.
### [Multisig-signer](./apps/multisig-signer)
The utility dApp for validators wishing to add or remove themselves as a signer of the multisig contract.
# 🧱 Libraries in this repo
### [UI toolkit](./libs/ui-toolkit)
@@ -86,14 +82,13 @@ Run `yarn nx run <my-app>-e2e:e2e` to execute the e2e tests with [cypress](https
Run `nx test my-app` to execute the unit tests with [Jest](https://jestjs.io), or `nx affected:test` to execute just unit tests affected by a change. You can also use `--watch` with these test to run jest in watch mode, see [Jest executor](https://nx.dev/packages/jest/executors/jest) for all CLI flags.
### Using wallet
#### Trading app E2E tests
To run tests locally using your own wallets you can add the following environment variables to `cypress.json`
1. Change `TRADING_TEST_VEGA_WALLET_NAME` to your Vega wallet name
2. Add `TRADING_TEST_VEGA_WALLET_PASSPHRASE` as your wallet passphrase
3. Add `ETH_WALLET_MNEMONIC` as your Ethereum wallet mnemonic
4. Use [vegawallet-dummy](https://github.com/vegaprotocol/vegawallet-dummy) to avoid being prompted in CLI during test execution.
### Formatting
+26 -9
View File
@@ -1,9 +1,26 @@
# App configuration variables
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET3
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
NX_VEGA_WALLET_URL=http://localhost:1789
CYPRESS_VEGA_ENV=STAGNET3
# React Environment Variables
# https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#expanding-environment-variables-in-env
# Netlify Environment Variables
# https://www.netlify.com/docs/continuous-deployment/#environment-variables
NX_VERSION=$npm_package_version
NX_REPOSITORY_URL=$REPOSITORY_URL
NX_BRANCH=$BRANCH
NX_PULL_REQUEST=$PULL_REQUEST
NX_HEAD=$HEAD
NX_COMMIT_REF=$COMMIT_REF
NX_CONTEXT=$CONTEXT
NX_REVIEW_ID=$REVIEW_ID
NX_INCOMING_HOOK_TITLE=$INCOMING_HOOK_TITLE
NX_INCOMING_HOOK_URL=$INCOMING_HOOK_URL
NX_INCOMING_HOOK_BODY=$INCOMING_HOOK_BODY
NX_URL=$URL
NX_DEPLOY_URL=$DEPLOY_URL
NX_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
NX_VEGA_ENV=TESTNET
NX_VEGA_WALLET_URL=http://localhost:1789/api/v1
+2 -2
View File
@@ -25,7 +25,7 @@ module.exports = defineConfig({
env: {
TRADING_TEST_VEGA_WALLET_NAME: 'UI_Trading_Test',
ETHEREUM_PROVIDER_URL:
'https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
VEGA_PUBLIC_KEY:
'47836c253520d2661bf5bed6339c0de08fd02cf5d4db0efee3b4373f20c7d278',
VEGA_PUBLIC_KEY2:
@@ -33,7 +33,7 @@ module.exports = defineConfig({
TRUNCATED_VEGA_PUBLIC_KEY: '47836c…c7d278',
TRUNCATED_VEGA_PUBLIC_KEY2: '1a18cd…0cf2e4',
ETHEREUM_WALLET_ADDRESS: '0x265Cc6d39a1B53d0d92068443009eE7410807158',
ETHERSCAN_URL: 'https://sepolia.etherscan.io',
ETHERSCAN_URL: 'https://ropsten.etherscan.io',
tsConfig: 'tsconfig.json',
TAGS: 'not @todo and not @ignore and not @manual',
TRADING_TEST_VEGA_WALLET_PASSPHRASE: '123',
-1
View File
@@ -1 +0,0 @@
declare module '*.scss';
@@ -1,17 +1,5 @@
import { aliasQuery } from '@vegaprotocol/cypress';
import {
generateSimpleMarkets,
generateMarketsCandles,
} from '../support/mocks/generate-markets';
describe('simple trading app', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'Markets', generateSimpleMarkets());
aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
});
cy.visit('/');
});
beforeEach(() => cy.visit('/'));
it('render', () => {
cy.get('#root').should('exist');
@@ -1,8 +1,9 @@
import { aliasQuery } from '@vegaprotocol/cypress';
import type { MarketsQuery } from '@vegaprotocol/market-list';
import type { Markets } from '@vegaprotocol/market-list';
import {
generateLongListMarkets,
generateSimpleMarkets,
generateMarketsData,
generateMarketsCandles,
} from '../support/mocks/generate-markets';
@@ -11,7 +12,8 @@ describe('market list', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'Markets', generateSimpleMarkets());
aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
aliasQuery(req, 'MarketsDataQuery', generateMarketsData());
aliasQuery(req, 'MarketsCandlesQuery', generateMarketsCandles());
});
cy.visit('/markets');
});
@@ -66,7 +68,8 @@ describe('market list', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'Markets', generateSimpleMarkets());
aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
aliasQuery(req, 'MarketsDataQuery', generateMarketsData());
aliasQuery(req, 'MarketsCandlesQuery', generateMarketsCandles());
});
});
@@ -78,10 +81,10 @@ describe('market list', { tags: '@smoke' }, () => {
it('last asset (if exists)', () => {
cy.visit('/markets');
cy.wait('@Markets').then((filters) => {
const data: MarketsQuery | undefined = filters?.response?.body?.data;
if (data?.marketsConnection?.edges.length) {
const data: Markets | undefined = filters?.response?.body?.data;
if (data.marketsConnection.edges.length) {
const asset =
data?.marketsConnection?.edges[0].node.tradableInstrument.instrument
data.marketsConnection.edges[0].node.tradableInstrument.instrument
.product.settlementAsset.symbol;
cy.visit(`/markets/Suspended/Future/${asset}`);
cy.getByTestId('market-assets-menu')
@@ -104,7 +107,8 @@ describe('market list', { tags: '@smoke' }, () => {
cy.viewport(1440, 900);
cy.mockGQL((req) => {
aliasQuery(req, 'Markets', generateLongListMarkets(1000));
aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
aliasQuery(req, 'MarketsDataQuery', generateMarketsData());
aliasQuery(req, 'MarketsCandlesQuery', generateMarketsCandles());
});
performance.mark('start-1k');
cy.visit('/markets');
@@ -1,12 +1,11 @@
import { connectVegaWallet } from '../support/vega-wallet';
import { connectVegaWallet } from '../support/connect-wallet';
import { aliasQuery } from '@vegaprotocol/cypress';
import {
generateMarket,
generateMarketData,
generateMarketsCandles,
generateMarketsData,
generateSimpleMarkets,
} from '../support/mocks/generate-markets';
import { generateDealTicket } from '../support/mocks/generate-deal-ticket';
import { generateMarketTags } from '../support/mocks/generate-market-tags';
import { generateMarketPositions } from '../support/mocks/generate-market-positions';
import { generateEstimateOrder } from '../support/mocks/generate-estimate-order';
@@ -15,25 +14,20 @@ import { generatePartyMarketData } from '../support/mocks/generate-party-market-
import { generateMarketMarkPrice } from '../support/mocks/generate-market-mark-price';
import { generateMarketNames } from '../support/mocks/generate-market-names';
import { generateMarketDepth } from '../support/mocks/generate-market-depth';
import type { Market, MarketsQuery } from '@vegaprotocol/market-list';
import { generateChainId } from '../support/mocks/generate-chain-id';
import { generateStatistics } from '../support/mocks/generate-statistics';
import type { Market, Markets } from '@vegaprotocol/market-list';
describe('market selector', { tags: '@smoke' }, () => {
let markets: Market[];
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'ChainId', generateChainId());
aliasQuery(req, 'Statistics', generateStatistics());
aliasQuery(req, 'Markets', generateSimpleMarkets());
aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'MarketData', generateMarketData());
aliasQuery(req, 'Market', generateMarket());
aliasQuery(req, 'MarketsCandlesQuery', generateMarketsCandles());
aliasQuery(req, 'MarketsDataQuery', generateMarketsData());
aliasQuery(req, 'DealTicket', generateDealTicket());
aliasQuery(req, 'MarketTags', generateMarketTags());
aliasQuery(req, 'MarketPositions', generateMarketPositions());
aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
aliasQuery(req, 'PartyBalance', generatePartyBalance());
aliasQuery(req, 'PartyBalanceQuery', generatePartyBalance());
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
aliasQuery(req, 'MarketNames', generateMarketNames());
@@ -42,9 +36,9 @@ describe('market selector', { tags: '@smoke' }, () => {
cy.visit('/markets');
cy.wait('@Markets').then((response) => {
const data: MarketsQuery | undefined = response?.response?.body?.data;
if (data?.marketsConnection?.edges.length) {
markets = data?.marketsConnection?.edges.map((edge) => edge.node);
const data: Markets | undefined = response?.response?.body?.data;
if (data.marketsConnection.edges.length) {
markets = data.marketsConnection.edges.map((edge) => edge.node);
}
});
});
@@ -138,9 +132,7 @@ describe('market selector', { tags: '@smoke' }, () => {
cy.get('[role="dialog"]').should('not.exist');
cy.getByTestId('arrow-button').click();
cy.get('[role="dialog"]').should('be.visible');
cy.get('input[placeholder="Search"]').then((search) => {
cy.wrap(search).clear();
});
cy.get('input[placeholder="Search"]').clear();
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
@@ -1,12 +1,10 @@
import { connectVegaWallet } from '../support/vega-wallet';
import { aliasQuery } from '@vegaprotocol/cypress';
import {
generateSimpleMarkets,
generateMarketsCandles,
generateMarketsData,
generateMarket,
generateMarketData,
} from '../support/mocks/generate-markets';
import { generateDealTicket } from '../support/mocks/generate-deal-ticket';
import { generateMarketTags } from '../support/mocks/generate-market-tags';
import { generateMarketPositions } from '../support/mocks/generate-market-positions';
import { generateEstimateOrder } from '../support/mocks/generate-estimate-order';
@@ -14,35 +12,31 @@ import { generatePartyBalance } from '../support/mocks/generate-party-balance';
import { generatePartyMarketData } from '../support/mocks/generate-party-market-data';
import { generateMarketMarkPrice } from '../support/mocks/generate-market-mark-price';
import { generateMarketDepth } from '../support/mocks/generate-market-depth';
import type { MarketsQuery, Market } from '@vegaprotocol/market-list';
import { generateChainId } from '../support/mocks/generate-chain-id';
import { generateStatistics } from '../support/mocks/generate-statistics';
import { connectVegaWallet } from '../support/connect-wallet';
import type { Markets, Market } from '@vegaprotocol/market-list';
describe('Market trade', { tags: '@smoke' }, () => {
let markets: Market[];
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'ChainId', generateChainId());
aliasQuery(req, 'Statistics', generateStatistics());
aliasQuery(req, 'Markets', generateSimpleMarkets());
aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'MarketsCandlesQuery', generateMarketsCandles());
aliasQuery(req, 'MarketsDataQuery', generateMarketsData());
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
aliasQuery(req, 'DealTicket', generateDealTicket());
aliasQuery(req, 'MarketTags', generateMarketTags());
aliasQuery(req, 'MarketPositions', generateMarketPositions());
aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
aliasQuery(req, 'PartyBalance', generatePartyBalance());
aliasQuery(req, 'PartyBalanceQuery', generatePartyBalance());
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
aliasQuery(req, 'MarketDepth', generateMarketDepth());
aliasQuery(req, 'Market', generateMarket());
aliasQuery(req, 'MarketData', generateMarketData());
});
cy.visit('/markets');
cy.wait('@Markets').then((response) => {
const data: MarketsQuery | undefined = response?.response?.body?.data;
if (data?.marketsConnection?.edges.length) {
markets = data?.marketsConnection?.edges.map((edge) => edge.node);
const data: Markets | undefined = response?.response?.body?.data;
if (data.marketsConnection.edges.length) {
markets = data.marketsConnection.edges.map((edge) => edge.node);
}
});
});
@@ -273,7 +267,7 @@ describe('Market trade', { tags: '@smoke' }, () => {
cy.get('#step-2-panel')
.find('dd')
.eq(3)
.should('have.text', '3.00 (3.03%)');
.should('have.text', '3.00000 (3.03%)');
}
});
@@ -298,11 +292,15 @@ describe('Market trade', { tags: '@smoke' }, () => {
cy.get('#step-3-panel')
.find('dd')
.eq(3)
.should('have.text', '3.00 (3.03%)');
.should('have.text', '3.00000 (3.03%)');
cy.get('#step-3-panel').find('dd').eq(4).should('have.text', ' - ');
cy.getByTestId('place-order').should('be.enabled').click();
cy.getByTestId('place-order').click();
cy.getByTestId('dialog-title').should(
'have.text',
'Confirm transaction in wallet'
);
}
});
@@ -1,23 +1,22 @@
import { connectVegaWallet } from '../support/vega-wallet';
import {
connectVegaWallet,
disconnectVegaWallet,
} from '../support/connect-wallet';
import { aliasQuery } from '@vegaprotocol/cypress';
import {
generatePositions,
emptyPositions,
generateMargins,
} from '../support/mocks/generate-positions';
import { generateAccounts } from '../support/mocks/generate-accounts';
import { generateAssets } from '../support/mocks/generate-assets';
import { generateOrders } from '../support/mocks/generate-orders';
import { generateFills } from '../support/mocks/generate-fills';
import {
generateFillsMarkets,
generateMarketsData,
generatePositionsMarkets,
} from '../support/mocks/generate-markets';
import { generateChainId } from '../support/mocks/generate-chain-id';
import { generateStatistics } from '../support/mocks/generate-statistics';
import { generateFillsMarkets } from '../support/mocks/generate-markets';
describe('Portfolio page', { tags: '@smoke' }, () => {
afterEach(() => {
disconnectVegaWallet();
});
describe('Portfolio page - wallet', { tags: '@smoke' }, () => {
it('button for wallet connect should work', () => {
cy.visit('/');
cy.get('[href="/portfolio"]').eq(0).click();
@@ -25,21 +24,6 @@ describe('Portfolio page - wallet', { tags: '@smoke' }, () => {
connectVegaWallet();
cy.getByTestId('trading-connect-wallet').should('not.exist');
});
});
describe('Portfolio page tabs', { tags: '@smoke' }, () => {
before(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'ChainId', generateChainId());
aliasQuery(req, 'Statistics', generateStatistics());
aliasQuery(req, 'Positions', generatePositions());
aliasQuery(req, 'Margins', generateMargins());
aliasQuery(req, 'Markets', generatePositionsMarkets());
aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'Assets', generateAssets());
});
});
it('certain tabs should exist', () => {
cy.visit('/portfolio');
@@ -62,23 +46,17 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
});
describe('Assets view', () => {
before(() => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'ChainId', generateChainId());
aliasQuery(req, 'Statistics', generateStatistics());
aliasQuery(req, 'Positions', generatePositions());
aliasQuery(req, 'Margins', generateMargins());
aliasQuery(req, 'Markets', generatePositionsMarkets());
aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'Assets', generateAssets());
});
cy.visit('/portfolio/assets');
connectVegaWallet();
});
it('data should be properly rendered', () => {
cy.get('.ag-center-cols-container .ag-row').should('have.length', 3);
cy.get('.ag-center-cols-container .ag-row').should('have.length', 5);
cy.get(
'.ag-center-cols-container [row-id="ACCOUNT_TYPE_GENERAL-asset-id-null"]'
)
@@ -95,29 +73,22 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
describe('Positions view', () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'ChainId', generateChainId());
aliasQuery(req, 'Statistics', generateStatistics());
aliasQuery(req, 'Positions', generatePositions());
aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'Margins', generateMargins());
aliasQuery(req, 'Markets', generatePositionsMarkets());
aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'Assets', generateAssets());
});
cy.visit('/portfolio/positions');
connectVegaWallet();
});
it('data should be properly rendered', () => {
cy.get('.ag-center-cols-container .ag-row').should('have.length', 2);
cy.getByTestId('positions-asset-tDAI').should('exist');
cy.getByTestId('positions-asset-tEURO').should('exist');
});
});
describe('Orders view', () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'ChainId', generateChainId());
aliasQuery(req, 'Statistics', generateStatistics());
aliasQuery(req, 'Orders', generateOrders());
aliasQuery(req, 'Markets', generateFillsMarkets());
});
@@ -133,8 +104,6 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
describe('Fills view', () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'ChainId', generateChainId());
aliasQuery(req, 'Statistics', generateStatistics());
aliasQuery(req, 'Fills', generateFills());
aliasQuery(req, 'Markets', generateFillsMarkets());
});
@@ -150,8 +119,6 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
describe('Empty views', () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'ChainId', generateChainId());
aliasQuery(req, 'Statistics', generateStatistics());
aliasQuery(req, 'Positions', emptyPositions());
aliasQuery(req, 'Accounts', { party: null });
aliasQuery(req, 'Orders', { party: null });
@@ -159,11 +126,6 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
aliasQuery(req, 'Markets', {
marketsConnection: { edges: [], __typename: 'MarketConnection' },
});
aliasQuery(req, 'Assets', {
assetsConnection: { edges: null, __typename: 'AssetsConnection' },
});
aliasQuery(req, 'Margins', generateMargins());
aliasQuery(req, 'MarketsData', generateMarketsData());
});
cy.visit('/portfolio');
connectVegaWallet();
@@ -171,26 +133,22 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
it('"No data to display" should be always displayed', () => {
cy.getByTestId('assets').click();
cy.get('div.flex.items-center.justify-center').should(
'contain.text',
cy.get('div.flex.items-center.justify-center').contains(
'No data to display'
);
cy.getByTestId('positions').click();
cy.get('div.flex.items-center.justify-center').should(
'contain.text',
cy.get('div.flex.items-center.justify-center').contains(
'No data to display'
);
cy.getByTestId('orders').click();
cy.get('div.flex.items-center.justify-center').should(
'contain.text',
cy.get('div.flex.items-center.justify-center').contains(
'No data to display'
);
cy.getByTestId('fills').click();
cy.get('div.flex.items-center.justify-center').should(
'contain.text',
cy.get('div.flex.items-center.justify-center').contains(
'No data to display'
);
});
@@ -2,11 +2,15 @@ export const connectVegaWallet = () => {
const form = 'rest-connector-form';
const walletName = Cypress.env('TRADING_TEST_VEGA_WALLET_NAME');
const walletPassphrase = Cypress.env('TRADING_TEST_VEGA_WALLET_PASSPHRASE');
cy.getByTestId('connect-vega-wallet').click();
cy.getByTestId('connectors-list')
.find('[data-testid="connector-gui"]')
.click();
cy.getByTestId('connectors-list').find('button').click();
cy.getByTestId(form).find('#wallet').click().type(walletName);
cy.getByTestId(form).find('#passphrase').click().type(walletPassphrase);
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
};
export const disconnectVegaWallet = () => {
cy.getByTestId('connect-vega-wallet').click();
cy.getByTestId('disconnect').click();
};
@@ -18,19 +18,4 @@ import 'cypress-real-events/support';
// Import commands.js using ES2015 syntax:
import './commands';
import registerCypressGrep from 'cypress-grep';
import { aliasQuery } from '@vegaprotocol/cypress';
registerCypressGrep();
before(() => {
// Mock chainId fetch which happens on every page for wallet connection
cy.mockGQL((req) => {
aliasQuery(req, 'ChainId', {
statistics: {
__typename: 'Statistics',
chainId:
Cypress.env('VEGA_ENV').toLowerCase() ||
'vega-fairground-202210041151',
},
});
});
});
@@ -1,6 +1,5 @@
import type { Market } from '@vegaprotocol/market-list';
import { Schema } from '@vegaprotocol/types';
import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list';
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
export const protoCandles = [
{ open: '9556163', close: '9587028', __typename: 'Candle' },
@@ -78,9 +77,9 @@ export const protoCandles = [
];
export const protoMarket: Market = {
id: 'ca7768f6de84bf86a21bbb6b0109d9659c81917b0e0339b2c262566c9b581a15',
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
state: Schema.MarketState.STATE_ACTIVE,
id: 'first-btcusd-id',
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
state: MarketState.STATE_ACTIVE,
decimalPlaces: 5,
positionDecimalPlaces: 0,
marketTimestamps: {
@@ -116,12 +115,7 @@ export const protoMarket: Market = {
product: {
__typename: 'Future',
quoteName: 'DAI',
settlementAsset: {
__typename: 'Asset',
id: 'asset-id',
symbol: 'tDAI',
decimals: 5,
},
settlementAsset: { symbol: 'tDAI', __typename: 'Asset', decimals: 5 },
},
__typename: 'Instrument',
},
@@ -129,28 +123,3 @@ export const protoMarket: Market = {
},
__typename: 'Market',
};
export const singleMarket: SingleMarketFieldsFragment = {
...protoMarket,
tradableInstrument: {
...protoMarket.tradableInstrument,
instrument: {
...protoMarket.tradableInstrument.instrument,
product: {
...protoMarket.tradableInstrument.instrument.product,
settlementAsset: {
...protoMarket.tradableInstrument.instrument.product.settlementAsset,
id: 'dai-id',
name: 'DAI Name',
},
dataSourceSpecForTradingTermination: {
id: 'oid',
},
},
},
},
depth: {
__typename: 'MarketDepth',
lastTrade: { price: '9893006', __typename: 'Trade' },
},
};
@@ -1,6 +1,6 @@
import merge from 'lodash/merge';
import type { AccountsQuery } from '@vegaprotocol/accounts';
import { Schema as Types } from '@vegaprotocol/types';
import { AccountType } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
export const generateAccounts = (
@@ -10,85 +10,98 @@ export const generateAccounts = (
party: {
__typename: 'Party',
id: Cypress.env('VEGA_PUBLIC_KEY'),
accountsConnection: {
__typename: 'AccountsConnection',
edges: [
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: null,
asset: {
__typename: 'Asset',
id: 'asset-id',
accounts: [
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: null,
asset: {
__typename: 'Asset',
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
},
},
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: {
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'AAVEDAI Monthly (30 Jun 2022)',
},
},
__typename: 'Market',
},
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: {
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
__typename: 'Market',
},
asset: {
__typename: 'Asset',
id: 'asset-id-2',
asset: {
__typename: 'Asset',
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
},
},
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_MARGIN,
balance: '1000',
market: {
__typename: 'Market',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: '',
},
},
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
},
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Types.AccountType.ACCOUNT_TYPE_MARGIN,
balance: '1000',
market: {
__typename: 'Market',
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
},
asset: {
__typename: 'Asset',
id: 'asset-id',
asset: {
__typename: 'Asset',
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
},
},
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_MARGIN,
balance: '1000',
market: {
__typename: 'Market',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: '',
},
},
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
},
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Types.AccountType.ACCOUNT_TYPE_MARGIN,
balance: '1000',
market: {
__typename: 'Market',
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
},
asset: {
__typename: 'Asset',
id: 'asset-id-2',
},
},
asset: {
__typename: 'Asset',
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
},
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: null,
asset: {
__typename: 'Asset',
id: 'asset-0',
},
},
},
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: null,
asset: {
__typename: 'Asset',
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
},
],
},
},
],
},
};
return merge(defaultAccounts, override);
@@ -1,120 +0,0 @@
import merge from 'lodash/merge';
import type { AssetsQuery } from '@vegaprotocol/assets';
import { Schema as Types } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
const defaultAssets: AssetsQuery = {
assetsConnection: {
edges: [
{
node: {
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
name: 'Euro',
source: {
__typename: 'ERC20',
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
lifetimeLimit: '1',
withdrawThreshold: '2',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '1',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'AccountBalance',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'AccountBalance',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'AccountBalance',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'AccountBalance',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'AccountBalance',
},
__typename: 'Asset',
},
},
{
node: {
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
name: 'DAI',
source: {
__typename: 'ERC20',
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
lifetimeLimit: '1',
withdrawThreshold: '2',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '1',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'AccountBalance',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'AccountBalance',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'AccountBalance',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'AccountBalance',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'AccountBalance',
},
__typename: 'Asset',
},
},
{
node: {
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
name: 'Asto',
source: {
__typename: 'BuiltinAsset',
maxFaucetAmountMint: '3',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '0',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: null,
takerFeeRewardAccount: null,
makerFeeRewardAccount: null,
lpFeeRewardAccount: null,
marketProposerRewardAccount: null,
__typename: 'Asset',
},
},
],
},
};
return merge(defaultAssets, override);
};
@@ -1,16 +0,0 @@
import type { ChainIdQuery } from '@vegaprotocol/react-helpers';
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
export const generateChainId = (
override?: PartialDeep<ChainIdQuery>
): ChainIdQuery => {
const defaultResult = {
statistics: {
__typename: 'Statistics',
chainId: Cypress.env('VEGA_ENV').toLowerCase() || 'test-chain-id',
},
};
return merge(defaultResult, override);
};
@@ -0,0 +1,33 @@
export const generateDealTicket = () => {
return {
market: {
id: 'first-btcusd-id',
decimalPlaces: 5,
positionDecimalPlaces: 0,
state: 'STATE_ACTIVE',
tradingMode: 'Continuous',
tradableInstrument: {
instrument: {
name: 'AAVEDAI Monthly (30 Jun 2022)',
product: {
quoteName: 'DAI',
settlementAsset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
name: 'tDAI TEST',
__typename: 'Asset',
},
__typename: 'Future',
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
depth: {
lastTrade: { price: '9893006', __typename: 'Trade' },
__typename: 'MarketDepth',
},
__typename: 'Market',
},
};
};
@@ -1,5 +1,5 @@
import type { FillsQuery, FillFieldsFragment } from '@vegaprotocol/fills';
import { Schema } from '@vegaprotocol/types';
import { Side } from '@vegaprotocol/types';
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
@@ -17,7 +17,7 @@ export const generateFills = (
seller: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
},
aggressor: Schema.Side.SIDE_SELL,
aggressor: Side.SIDE_SELL,
buyerFee: {
infrastructureFee: '5000',
},
@@ -30,11 +30,11 @@ export const generateFills = (
seller: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
},
aggressor: Schema.Side.SIDE_BUY,
aggressor: Side.SIDE_BUY,
}),
generateFill({
id: '3',
aggressor: Schema.Side.SIDE_SELL,
aggressor: Side.SIDE_SELL,
market: {
id: 'market-2',
},
@@ -80,7 +80,7 @@ export const generateFill = (override?: PartialDeep<FillFieldsFragment>) => {
size: '50000',
buyOrder: 'buy-order',
sellOrder: 'sell-order',
aggressor: Schema.Side.SIDE_BUY,
aggressor: Side.SIDE_BUY,
buyer: {
__typename: 'Party',
id: 'buyer-id',
@@ -1,12 +1,12 @@
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
import type { MarketDepthQuery } from '../../../../../libs/market-depth/src/lib/__generated___/MarketDepth';
import type { MarketDepth } from '../../../../../libs/market-depth/src/lib/__generated__/MarketDepth';
export const generateMarketDepth = (
override?: PartialDeep<MarketDepthQuery>
): MarketDepthQuery => {
const defaultResult: MarketDepthQuery = {
override?: PartialDeep<MarketDepth>
): MarketDepth => {
const defaultResult: MarketDepth = {
market: {
id: 'a46bd7e5277087723b7ab835844dec3cef8b4445738101269624bf5537d5d423',
depth: {
@@ -1,44 +1,31 @@
import type { MarketPositionsQuery } from '@vegaprotocol/deal-ticket';
import { Schema } from '@vegaprotocol/types';
export const generateMarketPositions = (): MarketPositionsQuery => {
export const generateMarketPositions = () => {
return {
party: {
id: '2e1ef32e5804e14232406aebaad719087d326afa5c648b7824d0823d8a46c8d1',
accountsConnection: {
__typename: 'AccountsConnection',
edges: [
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL,
asset: {
decimals: 5,
},
balance: '400000000000000000000',
market: {
id: '2751c508f9759761f912890f37fb3f97a00300bf7685c02a56a86e05facfe221',
__typename: 'Market',
},
},
accounts: [
{
type: 'General',
asset: {
decimals: 5,
},
{
__typename: 'AccountEdge',
node: {
type: Schema.AccountType.ACCOUNT_TYPE_MARGIN,
asset: {
decimals: 5,
},
balance: '265329',
market: {
id: 'ca7768f6de84bf86a21bbb6b0109d9659c81917b0e0339b2c262566c9b581a15',
__typename: 'Market',
},
},
balance: '400000000000000000000',
market: {
id: '2751c508f9759761f912890f37fb3f97a00300bf7685c02a56a86e05facfe221',
__typename: 'Market',
},
],
},
},
{
type: 'Margin',
asset: {
decimals: 5,
},
balance: '265329',
market: {
id: 'first-btcusd-id',
__typename: 'Market',
},
},
],
positionsConnection: {
edges: [
{
@@ -56,7 +43,7 @@ export const generateMarketPositions = (): MarketPositionsQuery => {
node: {
openVolume: '12',
market: {
id: 'ca7768f6de84bf86a21bbb6b0109d9659c81917b0e0339b2c262566c9b581a15',
id: 'first-btcusd-id',
__typename: 'Market',
},
__typename: 'Position',
File diff suppressed because it is too large Load Diff
@@ -1,12 +1,18 @@
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
import type { OrdersQuery, OrderFieldsFragment } from '@vegaprotocol/orders';
import { Schema } from '@vegaprotocol/types';
import type {
Orders,
Orders_party_ordersConnection_edges_node,
} from '@vegaprotocol/orders';
import {
OrderStatus,
OrderTimeInForce,
OrderType,
Side,
} from '@vegaprotocol/types';
export const generateOrders = (
override?: PartialDeep<OrdersQuery>
): OrdersQuery => {
const orders: OrderFieldsFragment[] = [
export const generateOrders = (override?: PartialDeep<Orders>): Orders => {
const orders: Orders_party_ordersConnection_edges_node[] = [
{
__typename: 'Order',
id: '066468C06549101DAF7BC51099E1412A0067DC08C246B7D8013C9D0CBF1E8EE7',
@@ -15,18 +21,16 @@ export const generateOrders = (
id: 'market-0',
},
size: '10',
type: Schema.OrderType.TYPE_LIMIT,
status: Schema.OrderStatus.STATUS_FILLED,
side: Schema.Side.SIDE_BUY,
type: OrderType.TYPE_LIMIT,
status: OrderStatus.STATUS_FILLED,
side: Side.SIDE_BUY,
remaining: '0',
price: '20000000',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
createdAt: new Date(2020, 1, 30).toISOString(),
updatedAt: null,
expiresAt: null,
rejectionReason: null,
liquidityProvision: null,
peggedOrder: null,
},
{
__typename: 'Order',
@@ -36,18 +40,16 @@ export const generateOrders = (
id: 'market-1',
},
size: '1',
type: Schema.OrderType.TYPE_LIMIT,
status: Schema.OrderStatus.STATUS_FILLED,
side: Schema.Side.SIDE_BUY,
type: OrderType.TYPE_LIMIT,
status: OrderStatus.STATUS_FILLED,
side: Side.SIDE_BUY,
remaining: '0',
price: '100',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
createdAt: new Date(2020, 1, 29).toISOString(),
updatedAt: null,
expiresAt: null,
rejectionReason: null,
liquidityProvision: null,
peggedOrder: null,
},
{
__typename: 'Order',
@@ -57,18 +59,16 @@ export const generateOrders = (
id: 'market-2',
},
size: '1',
type: Schema.OrderType.TYPE_LIMIT,
status: Schema.OrderStatus.STATUS_FILLED,
side: Schema.Side.SIDE_BUY,
type: OrderType.TYPE_LIMIT,
status: OrderStatus.STATUS_FILLED,
side: Side.SIDE_BUY,
remaining: '0',
price: '20000',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
createdAt: new Date(2020, 1, 28).toISOString(),
updatedAt: null,
expiresAt: null,
rejectionReason: null,
liquidityProvision: null,
peggedOrder: null,
},
{
__typename: 'Order',
@@ -78,18 +78,16 @@ export const generateOrders = (
id: 'market-3',
},
size: '1',
type: Schema.OrderType.TYPE_LIMIT,
status: Schema.OrderStatus.STATUS_ACTIVE,
side: Schema.Side.SIDE_BUY,
type: OrderType.TYPE_LIMIT,
status: OrderStatus.STATUS_ACTIVE,
side: Side.SIDE_BUY,
remaining: '0',
price: '100000',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
createdAt: new Date(2020, 1, 27).toISOString(),
updatedAt: null,
expiresAt: null,
rejectionReason: null,
liquidityProvision: null,
peggedOrder: null,
},
{
__typename: 'Order',
@@ -99,22 +97,20 @@ export const generateOrders = (
id: 'market-3',
},
size: '10',
type: Schema.OrderType.TYPE_LIMIT,
status: Schema.OrderStatus.STATUS_PARTIALLY_FILLED,
side: Schema.Side.SIDE_SELL,
type: OrderType.TYPE_LIMIT,
status: OrderStatus.STATUS_PARTIALLY_FILLED,
side: Side.SIDE_SELL,
remaining: '3',
price: '100000',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
createdAt: new Date(2020, 1, 27).toISOString(),
updatedAt: null,
expiresAt: null,
liquidityProvision: null,
peggedOrder: null,
rejectionReason: null,
},
];
const defaultResult: OrdersQuery = {
const defaultResult: Orders = {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
ordersConnection: {
@@ -1,81 +1,57 @@
import merge from 'lodash/merge';
import type { PartyBalanceQuery } from '@vegaprotocol/deal-ticket';
import type { PartialDeep } from 'type-fest';
import { Schema as Types } from '@vegaprotocol/types';
export const generatePartyBalance = (
override?: PartialDeep<PartyBalanceQuery>
): PartyBalanceQuery => {
const defaultResult: PartyBalanceQuery = {
export const generatePartyBalance = () => {
return {
party: {
accountsConnection: {
__typename: 'AccountsConnection',
edges: [
{
__typename: 'AccountEdge',
node: {
balance: '88474051',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
asset: {
id: 'dai-id',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
},
accounts: [
{
balance: '88474051',
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
{
__typename: 'AccountEdge',
node: {
balance: '100000000',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
asset: {
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
symbol: 'tEURO',
name: 'tEURO TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
},
__typename: 'Account',
},
{
balance: '100000000',
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
symbol: 'tEURO',
name: 'tEURO TEST',
decimals: 5,
__typename: 'Asset',
},
{
__typename: 'AccountEdge',
node: {
balance: '3412867',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
asset: {
id: 'dai-id',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
},
__typename: 'Account',
},
{
balance: '3412867',
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
{
__typename: 'AccountEdge',
node: {
balance: '70007',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
asset: {
id: 'dai-id',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
},
__typename: 'Account',
},
{
balance: '70007',
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
],
},
__typename: 'Account',
},
],
__typename: 'Party',
},
};
return merge(defaultResult, override);
};
@@ -1,39 +1,18 @@
import type { PartyMarketDataQuery } from '@vegaprotocol/deal-ticket';
import { Schema as Types } from '@vegaprotocol/types';
export const generatePartyMarketData = (): PartyMarketDataQuery => {
export const generatePartyMarketData = () => {
return {
party: {
id: '2e1ef32e5804e14232406aebaad719087d326afa5c648b7824d0823d8a46c8d1',
accountsConnection: {
__typename: 'AccountsConnection',
edges: [
{
__typename: 'AccountEdge',
node: {
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '1200000',
asset: { id: 'fBTC', decimals: 5, __typename: 'Asset' },
market: null,
__typename: 'AccountBalance',
},
},
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '0.000000001',
asset: {
__typename: 'Asset',
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
decimals: 0,
},
},
},
],
},
accounts: [
{
type: 'General',
balance: '1200000',
asset: { id: 'fBTC', decimals: 5, __typename: 'Asset' },
market: null,
__typename: 'Account',
},
],
marginsConnection: { edges: null, __typename: 'MarginConnection' },
positionsConnection: { edges: null, __typename: 'PositionConnection' },
__typename: 'Party',
},
};
@@ -1,15 +1,15 @@
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
import type {
PositionsQuery,
PositionFieldsFragment,
MarginsQuery,
Positions,
Positions_party_positionsConnection_edges_node,
} from '@vegaprotocol/positions';
import { MarketTradingMode } from '@vegaprotocol/types';
export const generatePositions = (
override?: PartialDeep<PositionsQuery>
): PositionsQuery => {
const nodes: PositionFieldsFragment[] = [
override?: PartialDeep<Positions>
): Positions => {
const nodes: Positions_party_positionsConnection_edges_node[] = [
{
__typename: 'Position',
realisedPNL: '0',
@@ -17,8 +17,49 @@ export const generatePositions = (
unrealisedPNL: '895000',
averageEntryPrice: '1129935',
updatedAt: '2022-07-28T15:09:34.441143Z',
marginsConnection: {
__typename: 'MarginConnection',
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
},
asset: {
__typename: 'Asset',
symbol: 'tDAI',
},
},
},
],
},
market: {
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
data: {
markPrice: '17588787',
__typename: 'MarketData',
market: {
__typename: 'Market',
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
},
},
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'UNIDAI Monthly (30 Jun 2022)',
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market',
},
},
@@ -29,8 +70,49 @@ export const generatePositions = (
unrealisedPNL: '895000',
averageEntryPrice: '8509338',
updatedAt: '2022-07-28T15:09:34.441143Z',
marginsConnection: {
__typename: 'MarginConnection',
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
},
asset: {
__typename: 'Asset',
symbol: 'tDAI',
},
},
},
],
},
market: {
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
data: {
markPrice: '8649338',
__typename: 'MarketData',
market: {
__typename: 'Market',
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
},
},
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'AAVEDAI Monthly (30 Jun 2022)',
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market',
},
},
@@ -40,15 +122,56 @@ export const generatePositions = (
unrealisedPNL: '-22519',
averageEntryPrice: '84400088',
updatedAt: '2022-07-28T14:53:54.725477Z',
marginsConnection: {
__typename: 'MarginConnection',
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
},
asset: {
__typename: 'Asset',
symbol: 'tEURO',
},
},
},
],
},
market: {
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
data: {
markPrice: '84377569',
__typename: 'MarketData',
market: {
__typename: 'Market',
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
},
},
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'Tesla Quarterly (30 Jun 2022)',
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market',
},
__typename: 'Position',
},
];
const defaultResult: PositionsQuery = {
const defaultResult: Positions = {
party: {
__typename: 'Party',
id: Cypress.env('VEGA_PUBLIC_KEY'),
@@ -67,7 +190,7 @@ export const generatePositions = (
return merge(defaultResult, override);
};
export const emptyPositions = (): PositionsQuery => {
export const emptyPositions = () => {
return {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
@@ -76,70 +199,3 @@ export const emptyPositions = (): PositionsQuery => {
},
};
};
export const generateMargins = (): MarginsQuery => {
return {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
marginsConnection: {
edges: [
{
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
},
asset: {
__typename: 'Asset',
id: 'tDAI-id',
},
},
},
{
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
},
asset: {
__typename: 'Asset',
id: 'tDAI-id',
},
},
__typename: 'MarginEdge',
},
{
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
},
asset: {
__typename: 'Asset',
id: 'tEURO-id',
},
},
__typename: 'MarginEdge',
},
],
__typename: 'MarginConnection',
},
__typename: 'Party',
},
};
};
@@ -1,17 +0,0 @@
import type { StatisticsQuery } from '@vegaprotocol/environment';
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
export const generateStatistics = (
override?: PartialDeep<StatisticsQuery>
): StatisticsQuery => {
const defaultResult = {
statistics: {
__typename: 'Statistics',
chainId: Cypress.env('VEGA_ENV').toLowerCase() || 'test-chain-id',
blockHeight: '11',
},
};
return merge(defaultResult, override);
};
+1 -2
View File
@@ -1,7 +1,6 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"strict": true,
"jsx": "react-jsx",
"sourceMap": false,
"allowSyntheticDefaultImports": true,
@@ -9,5 +8,5 @@
"allowJs": true,
"types": ["cypress", "node", "cypress-real-events", "cypress-grep"]
},
"include": ["src/**/*.ts", "src/**/*.js", "./declaration.d.ts"]
"include": ["src/**/*.ts", "src/**/*.js"]
}
+6 -6
View File
@@ -17,11 +17,11 @@ NX_INCOMING_HOOK_BODY=$INCOMING_HOOK_BODY
NX_URL=$URL
NX_DEPLOY_URL=$DEPLOY_URL
NX_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
NX_VEGA_CONFIG_URL="https://static.vega.xyz/assets/stagnet3-network.json"
NX_VEGA_ENV=STAGNET3
NX_VEGA_URL="https://api.stagnet3.vega.xyz/graphql"
NX_VEGA_WALLET_URL=http://localhost:1789
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_CONFIG_URL="https://static.vega.xyz/assets/testnet-network.json"
NX_VEGA_ENV = 'TESTNET'
NX_VEGA_URL="https://api.n11.testnet.vega.xyz/graphql"
NX_VEGA_WALLET_URL=http://localhost:1789/api/v1
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
NX_VEGA_NETWORKS={"MAINNET":"https://alpha.console.vega.xyz"}
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
+2 -2
View File
@@ -3,6 +3,6 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/devnet-network.json
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
NX_VEGA_ENV=DEVNET
NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\"}
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
-7
View File
@@ -1,7 +0,0 @@
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/sandbox-network.json
NX_VEGA_URL=https://api.sandbox.vega.xyz/graphql
NX_VEGA_ENV=SANDBOX
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","STAGNET1":"https://stagnet1.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/sandbox-network.json
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
-10
View File
@@ -1,10 +0,0 @@
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet1-network.json
NX_VEGA_ENV=STAGNET1
NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://stagnet1.console.vega.xyz\",\"STAGNET3\":\"https://stagnet3.console.vega.xyz\"}
NX_VEGA_TOKEN_URL=https://stagnet1.token.vega.xyz
NX_VEGA_URL=https://api.n00.stagnet1.vega.xyz/graphql
NX_VEGA_WALLET_URL=http://localhost:1789
+4 -4
View File
@@ -1,7 +1,7 @@
# App configuration variables
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_VEGA_URL=https://api.n01.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET3
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
NX_VEGA_EXPLORER_URL=https://staging2.explorer.vega.xyz
+2 -2
View File
@@ -3,6 +3,6 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json
NX_VEGA_URL=https://api.n12.testnet.vega.xyz/graphql
NX_VEGA_ENV=TESTNET
NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
-7
View File
@@ -77,13 +77,6 @@
"nx build console-lite"
]
}
},
"build-spec": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "yarn tsc --project ./apps/console-lite/tsconfig.spec.json"
}
}
},
"tags": []
+23 -48
View File
@@ -1,7 +1,6 @@
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { ThemeContext } from '@vegaprotocol/react-helpers';
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
import { createClient } from './lib/apollo-client';
import { EnvironmentProvider, NetworkLoader } from '@vegaprotocol/environment';
import {
VegaConnectDialog,
@@ -15,11 +14,9 @@ import Header from './components/header';
import { Main } from './components/main';
import LocalContext from './context/local-context';
import useLocalValues from './hooks/use-local-values';
import type { InMemoryCacheConfig } from '@apollo/client';
function App() {
const [theme, toggleTheme] = useThemeSwitcher();
const localValues = useLocalValues(theme, toggleTheme);
const localValues = useLocalValues();
const {
vegaWalletDialog,
menu: { setMenuOpen },
@@ -30,51 +27,29 @@ function App() {
setMenuOpen(false);
}, [location, setMenuOpen]);
const cacheConfig: InMemoryCacheConfig = {
typePolicies: {
Market: {
merge: true,
},
Party: {
merge: true,
},
Query: {},
Account: {
keyFields: false,
fields: {
balanceFormatted: {},
},
},
Node: {
keyFields: false,
},
Instrument: {
keyFields: false,
},
},
};
return (
<EnvironmentProvider>
<ThemeContext.Provider value={theme}>
<NetworkLoader cache={cacheConfig}>
<VegaWalletProvider>
<LocalContext.Provider value={localValues}>
<AppLoader>
<div className="max-h-full min-h-full dark:bg-lite-black dark:text-neutral-200 bg-white text-neutral-800 grid grid-rows-[min-content,1fr]">
<Header />
<Main />
<VegaConnectDialog connectors={Connectors} />
<VegaManageDialog
dialogOpen={vegaWalletDialog.manage}
setDialogOpen={vegaWalletDialog.setManage}
/>
</div>
</AppLoader>
</LocalContext.Provider>
</VegaWalletProvider>
</NetworkLoader>
</ThemeContext.Provider>
<NetworkLoader createClient={createClient}>
<VegaWalletProvider>
<LocalContext.Provider value={localValues}>
<AppLoader>
<div className="max-h-full min-h-full dark:bg-lite-black dark:text-neutral-200 bg-white text-neutral-800 grid grid-rows-[min-content,1fr]">
<Header />
<Main />
<VegaConnectDialog
connectors={Connectors}
dialogOpen={vegaWalletDialog.connect}
setDialogOpen={vegaWalletDialog.setConnect}
/>
<VegaManageDialog
dialogOpen={vegaWalletDialog.manage}
setDialogOpen={vegaWalletDialog.setManage}
/>
</div>
</AppLoader>
</LocalContext.Provider>
</VegaWalletProvider>
</NetworkLoader>
</EnvironmentProvider>
);
}
@@ -1,14 +1,8 @@
import React, {
forwardRef,
useCallback,
useContext,
useMemo,
useRef,
} from 'react';
import React, { forwardRef, useCallback, useMemo, useRef } from 'react';
import classNames from 'classnames';
import type { AgGridReact } from 'ag-grid-react';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
import { ThemeContext, useScreenDimensions } from '@vegaprotocol/react-helpers';
import { useScreenDimensions, useTheme } from '@vegaprotocol/react-helpers';
import type {
GridOptions,
GetRowIdParams,
@@ -43,7 +37,7 @@ const ConsoleLiteGrid = <T extends { id?: string }>(
) => {
const { isMobile, screenSize } = useScreenDimensions();
const gridRef = useRef<AgGridReact | null>(null);
const theme = useContext(ThemeContext);
const { theme } = useTheme();
const handleOnGridReady = useCallback(() => {
(
(ref as React.RefObject<AgGridReact>) || gridRef
@@ -105,7 +99,9 @@ const ConsoleLiteGrid = <T extends { id?: string }>(
);
};
const ConsoleLiteGridForwarder = forwardRef(ConsoleLiteGrid) as <T>(
const ConsoleLiteGridForwarder = forwardRef(ConsoleLiteGrid) as <
T extends { id?: string }
>(
p: Props<T> & { ref?: React.Ref<AgGridReact> }
) => React.ReactElement;
@@ -1,17 +1,13 @@
query PartyBalanceQuery($partyId: ID!) {
party(id: $partyId) {
accountsConnection {
edges {
node {
type
balance
asset {
id
symbol
name
decimals
}
}
accounts {
type
balance
asset {
id
symbol
name
decimals
}
}
}
@@ -0,0 +1,65 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
import { AccountType } from "@vegaprotocol/types";
// ====================================================
// GraphQL query operation: PartyBalanceQuery
// ====================================================
export interface PartyBalanceQuery_party_accounts_asset {
__typename: "Asset";
/**
* The ID of the asset
*/
id: string;
/**
* The symbol of the asset (e.g: GBP)
*/
symbol: string;
/**
* The full name of the asset (e.g: Great British Pound)
*/
name: string;
/**
* The precision of the asset. Should match the decimal precision of the asset on its native chain, e.g: for ERC20 assets, it is often 18
*/
decimals: number;
}
export interface PartyBalanceQuery_party_accounts {
__typename: "Account";
/**
* Account type (General, Margin, etc)
*/
type: AccountType;
/**
* Balance as string - current account balance (approx. as balances can be updated several times per second)
*/
balance: string;
/**
* Asset, the 'currency'
*/
asset: PartyBalanceQuery_party_accounts_asset;
}
export interface PartyBalanceQuery_party {
__typename: "Party";
/**
* Collateral accounts relating to a party
*/
accounts: PartyBalanceQuery_party_accounts[] | null;
}
export interface PartyBalanceQuery {
/**
* An entity that is trading on the Vega network
*/
party: PartyBalanceQuery_party | null;
}
export interface PartyBalanceQueryVariables {
partyId: string;
}
@@ -8,24 +8,20 @@ export type PartyBalanceQueryQueryVariables = Types.Exact<{
}>;
export type PartyBalanceQueryQuery = { __typename?: 'Query', party?: { __typename?: 'Party', accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } } } | null> | null } | null } | null };
export type PartyBalanceQueryQuery = { __typename?: 'Query', party?: { __typename?: 'Party', accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } }> | null } | null };
export const PartyBalanceQueryDocument = gql`
query PartyBalanceQuery($partyId: ID!) {
party(id: $partyId) {
accountsConnection {
edges {
node {
type
balance
asset {
id
symbol
name
decimals
}
}
accounts {
type
balance
asset {
id
symbol
name
decimals
}
}
}
@@ -19,17 +19,3 @@ export const EST_FEES_TOOLTIP_TEXT = t(
export const EST_SLIPPAGE = t(
'When you execute a trade on Vega, the price obtained in the market may differ from the best available price displayed at the time of placing the trade. The estimated slippage shows the difference between the best available price and the estimated execution price, determined by market liquidity and your chosen order size.'
);
export const ERROR_SIZE_DECIMAL = t(
'The size field accepts up to X decimal places'
);
export enum MarketModeValidationType {
PriceMonitoringAuction = 'PriceMonitoringAuction',
LiquidityMonitoringAuction = 'LiquidityMonitoringAuction',
Auction = 'Auction',
}
export enum AccountValidationType {
NoCollateral = 'NoCollateral',
}
@@ -1,11 +1,13 @@
import React from 'react';
import { render } from '@testing-library/react';
import type { AccountFragment } from '@vegaprotocol/deal-ticket';
import type {
PartyBalanceQuery_party_accounts,
PartyBalanceQuery_party_accounts_asset,
} from './__generated__/PartyBalanceQuery';
import { DealTicketBalance } from './deal-ticket-balance';
import { Schema } from '@vegaprotocol/types';
import type { MarketDealTicketAsset } from '@vegaprotocol/market-list';
import { AccountType } from '@vegaprotocol/types';
const tDAI: MarketDealTicketAsset = {
const tDAI: PartyBalanceQuery_party_accounts_asset = {
__typename: 'Asset',
id: '1',
symbol: 'tDAI',
@@ -13,10 +15,10 @@ const tDAI: MarketDealTicketAsset = {
decimals: 2,
};
const accounts: AccountFragment[] = [
const accounts: PartyBalanceQuery_party_accounts[] = [
{
__typename: 'AccountBalance',
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL,
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '1000000',
asset: tDAI,
},
@@ -1,13 +1,14 @@
import * as React from 'react';
import classNames from 'classnames';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import type { PartyBalanceQuery_party_accounts } from './__generated__/PartyBalanceQuery';
import { useSettlementAccount } from '../../hooks/use-settlement-account';
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
import { Schema } from '@vegaprotocol/types';
import type { AccountFragment } from '@vegaprotocol/deal-ticket';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { useSettlementAccount } from '@vegaprotocol/deal-ticket';
import { AccountType } from '@vegaprotocol/types';
interface DealTicketBalanceProps {
settlementAsset: MarketDealTicket['tradableInstrument']['instrument']['product']['settlementAsset'];
accounts: AccountFragment[];
settlementAsset: DealTicketMarketFragment['tradableInstrument']['instrument']['product']['settlementAsset'];
accounts: PartyBalanceQuery_party_accounts[];
isWalletConnected: boolean;
className?: string;
}
@@ -23,9 +24,9 @@ export const DealTicketBalance = ({
const settlementAccount = useSettlementAccount(
settlementAssetId,
accounts,
Schema.AccountType.ACCOUNT_TYPE_GENERAL
AccountType.ACCOUNT_TYPE_GENERAL
);
const formattedNumber =
const formatedNumber =
settlementAccount?.balance &&
settlementAccount.asset.decimals &&
addDecimalsFormatNumber(
@@ -36,7 +37,7 @@ export const DealTicketBalance = ({
const balance = (
<p className="text-blue text-lg font-semibold">
{settlementAccount
? t(`${formattedNumber}`)
? t(`${formatedNumber}`)
: `No ${settlementAssetSymbol} left to trade`}
</p>
);
@@ -1,89 +1,90 @@
import * as React from 'react';
import { useParams } from 'react-router-dom';
import compact from 'lodash/compact';
import { gql, useQuery } from '@apollo/client';
import {
DealTicketManager,
usePartyBalanceQuery,
DealTicketContainer as Container,
} from '@vegaprotocol/deal-ticket';
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
import { Loader } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { DealTicketSteps } from './deal-ticket-steps';
import { DealTicketBalance } from './deal-ticket-balance';
import Baubles from './baubles-decor';
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
import ConnectWallet from '../wallet-connector';
import { useMemo } from 'react';
import type {
MarketDataUpdateFieldsFragment,
MarketDealTicket,
} from '@vegaprotocol/market-list';
import { marketDealTicketProvider } from '@vegaprotocol/market-list';
const tempEmptyText = (
<p>{t('Please select a market from the markets page')}</p>
);
const PARTY_BALANCE_QUERY = gql`
query PartyBalanceQuery($partyId: ID!) {
party(id: $partyId) {
accounts {
type
balance
asset {
id
symbol
name
decimals
}
}
}
}
`;
export const DealTicketContainer = () => {
const { marketId } = useParams<{ marketId: string }>();
const { pubKey } = useVegaWallet();
const { keypair } = useVegaWallet();
const { data: partyData } = usePartyBalanceQuery({
variables: { partyId: pubKey || '' },
skip: !pubKey,
});
const variables = useMemo(
() => ({
marketId: marketId || '',
}),
[marketId]
);
const { data, loading } = useDataProvider<
MarketDealTicket,
MarketDataUpdateFieldsFragment
>({
dataProvider: marketDealTicketProvider,
variables,
skip: !marketId,
});
const accounts = compact(partyData?.party?.accountsConnection?.edges).map(
(e) => e.node
const { data: partyData, loading } = useQuery<PartyBalanceQuery>(
PARTY_BALANCE_QUERY,
{
variables: { partyId: keypair?.pub },
skip: !keypair?.pub,
}
);
const loader = <Loader />;
if (marketId && data) {
const balance = (
<DealTicketBalance
className="mb-4"
settlementAsset={
data.tradableInstrument.instrument.product?.settlementAsset
const container = marketId ? (
<Container marketId={marketId}>
{(data) => {
if (!data.market) {
return null as unknown as JSX.Element;
}
accounts={accounts || []}
isWalletConnected={!!pubKey}
/>
);
const container = (
<DealTicketManager market={data}>
{loading ? loader : balance}
<DealTicketSteps market={data} />
</DealTicketManager>
);
const balance = (
<DealTicketBalance
className="mb-4"
settlementAsset={
data.market.tradableInstrument.instrument.product?.settlementAsset
}
accounts={partyData?.party?.accounts || []}
isWalletConnected={!!keypair?.pub}
/>
);
return (
<section className="flex p-4 md:p-6">
<section className="w-full md:w-1/2 md:min-w-[500px]">
{pubKey ? container : <ConnectWallet />}
</section>
<Baubles />
</section>
);
}
return marketId ? (
<Splash>
<p>{t('Could not load market')}</p>
</Splash>
return (
<DealTicketManager market={data.market}>
{loading ? loader : balance}
<DealTicketSteps market={data.market} partyData={partyData} />
</DealTicketManager>
);
}}
</Container>
) : (
tempEmptyText
);
return (
<section className="flex p-4 md:p-6">
<section className="w-full md:w-1/2 md:min-w-[500px]">
{keypair ? container : <ConnectWallet />}
</section>
<Baubles />
</section>
);
};
@@ -1,9 +1,10 @@
import React from 'react';
import type { ReactNode } from 'react';
import { t } from '@vegaprotocol/react-helpers';
import { Icon, Tooltip, TrafficLight } from '@vegaprotocol/ui-toolkit';
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
import { IconNames } from '@blueprintjs/icons';
import * as constants from '../constants';
import * as constants from './constants';
import { TrafficLight } from '../traffic-light';
interface DealTicketEstimatesProps {
quoteName?: string;
@@ -16,6 +17,45 @@ interface DealTicketEstimatesProps {
slippage?: string;
}
interface DataTitleProps {
children: ReactNode;
quoteName?: string;
}
export const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
<dt>
{children}
{quoteName && <small> ({quoteName})</small>}
</dt>
);
interface ValueTooltipProps {
value?: string;
children?: ReactNode;
description: string;
id?: string;
}
export const ValueTooltipRow = ({
value,
children,
description,
id,
}: ValueTooltipProps) => (
<dd className="flex gap-x-2 items-center">
{value || children}
<Tooltip align="center" description={description}>
<div className="cursor-help" id={id || ''} tabIndex={-1}>
<Icon
name={IconNames.ISSUE}
className="block rotate-180"
ariaLabel={description}
/>
</div>
</Tooltip>
</dd>
);
export const DealTicketEstimates = ({
price,
quoteName,
@@ -91,42 +131,3 @@ export const DealTicketEstimates = ({
)}
</dl>
);
interface DataTitleProps {
children: ReactNode;
quoteName?: string;
}
export const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
<dt>
{children}
{quoteName && <small> ({quoteName})</small>}
</dt>
);
interface ValueTooltipProps {
value?: string;
children?: ReactNode;
description: string;
id?: string;
}
export const ValueTooltipRow = ({
value,
children,
description,
id,
}: ValueTooltipProps) => (
<dd className="flex gap-x-2 items-center">
{value || children}
<Tooltip align="center" description={description}>
<div className="cursor-help" id={id || ''} tabIndex={-1}>
<Icon
name={IconNames.ISSUE}
className="block rotate-180"
ariaLabel={description}
/>
</div>
</Tooltip>
</dd>
);
@@ -1,4 +1,5 @@
import { DealTicketEstimates } from '@vegaprotocol/deal-ticket';
import React from 'react';
import { DealTicketEstimates } from './deal-ticket-estimates';
import { DealTicketSizeInput } from './deal-ticket-size-input';
interface DealTicketSizeProps {
@@ -1,19 +1,11 @@
import React, { useCallback, useState } from 'react';
import { t } from '@vegaprotocol/react-helpers';
import {
Dialog,
Icon,
Intent,
Tooltip,
TrafficLight,
} from '@vegaprotocol/ui-toolkit';
import * as constants from './constants';
import { TrafficLight } from '../traffic-light';
import { Dialog, Icon, Intent, Tooltip } from '@vegaprotocol/ui-toolkit';
import { InputSetter } from '../../components/input-setter';
import { IconNames } from '@blueprintjs/icons';
import {
DataTitle,
ValueTooltipRow,
EST_SLIPPAGE,
} from '@vegaprotocol/deal-ticket';
import { DataTitle, ValueTooltipRow } from './deal-ticket-estimates';
interface DealTicketSlippageProps {
step?: number;
@@ -48,12 +40,12 @@ export const DealTicketSlippage = ({
const formLabel = (
<label className="flex items-center mb-1">
<span className="mr-1">{t('Adjust slippage tolerance')}</span>
<Tooltip align="center" description={EST_SLIPPAGE}>
<Tooltip align="center" description={constants.EST_SLIPPAGE}>
<div className="cursor-help" tabIndex={-1}>
<Icon
name={IconNames.ISSUE}
className="block rotate-180"
ariaLabel={EST_SLIPPAGE}
ariaLabel={constants.EST_SLIPPAGE}
/>
</div>
</Tooltip>
@@ -91,7 +83,7 @@ export const DealTicketSlippage = ({
<DataTitle>{t('Est. Price Impact / Slippage')}</DataTitle>
<div className="flex">
<div className="mr-1">
<ValueTooltipRow description={EST_SLIPPAGE}>
<ValueTooltipRow description={constants.EST_SLIPPAGE}>
<TrafficLight value={value} q1={1} q2={5}>
{value}%
</TrafficLight>
@@ -1,52 +1,50 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useForm, Controller } from 'react-hook-form';
import compact from 'lodash/compact';
import { Stepper } from '../stepper';
import {
getDefaultOrder,
useOrderCloseOut,
useOrderMargin,
usePartyBalanceQuery,
useMaximumPositionSize,
useCalculateSlippage,
validateAmount,
} from '@vegaprotocol/deal-ticket';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import { InputError } from '@vegaprotocol/ui-toolkit';
import { BigNumber } from 'bignumber.js';
import { MarketSelector } from '@vegaprotocol/deal-ticket';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { VegaTxStatus } from '@vegaprotocol/wallet';
import type { Order } from '@vegaprotocol/orders';
import { useVegaWallet, VegaTxStatus } from '@vegaprotocol/wallet';
import {
t,
addDecimalsFormatNumber,
toDecimal,
removeDecimal,
addDecimalsFormatNumber,
addDecimal,
formatNumber,
} from '@vegaprotocol/react-helpers';
import {
getDefaultOrder,
useOrderValidation,
useOrderSubmit,
getOrderDialogTitle,
getOrderDialogIntent,
getOrderDialogIcon,
OrderFeedback,
validateSize,
} from '@vegaprotocol/orders';
import { DealTicketSize } from './deal-ticket-size';
import MarketNameRenderer from '../simple-market-list/simple-market-renderer';
import SideSelector, { SIDE_NAMES } from './side-selector';
import ReviewTrade from './review-trade';
import { Schema } from '@vegaprotocol/types';
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
import useOrderCloseOut from '../../hooks/use-order-closeout';
import useOrderMargin from '../../hooks/use-order-margin';
import useMaximumPositionSize from '../../hooks/use-maximum-position-size';
import useCalculateSlippage from '../../hooks/use-calculate-slippage';
import { Side, OrderType } from '@vegaprotocol/types';
import { DealTicketSlippage } from './deal-ticket-slippage';
import { useOrderValidation } from './use-order-validation';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
interface DealTicketMarketProps {
market: MarketDealTicket;
market: DealTicketMarketFragment;
partyData?: PartyBalanceQuery;
}
export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
export const DealTicketSteps = ({
market,
partyData,
}: DealTicketMarketProps) => {
const navigate = useNavigate();
const setMarket = useCallback(
(marketId: string) => {
@@ -61,38 +59,35 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
watch,
setValue,
formState: { errors },
} = useForm<OrderSubmissionBody['orderSubmission']>({
} = useForm<Order>({
mode: 'onChange',
defaultValues: getDefaultOrder(market),
});
const emptyString = ' - ';
const step = toDecimal(market.positionDecimalPlaces);
const orderType = watch('type');
const orderTimeInForce = watch('timeInForce');
const orderSide = watch('side');
const orderSize = watch('size');
const order = watch();
const { pubKey } = useVegaWallet();
const estMargin = useOrderMargin({
order,
market,
partyId: pubKey || '',
});
const { message: invalidText, isDisabled } = useOrderValidation({
market,
order,
orderType,
orderTimeInForce,
fieldErrors: errors,
});
const { submit, transaction, finalizedOrder, Dialog } = useOrderSubmit();
const { data: partyBalance } = usePartyBalanceQuery({
variables: { partyId: pubKey || '' },
skip: !pubKey,
const { keypair } = useVegaWallet();
const estMargin = useOrderMargin({
order,
market,
partyId: keypair?.pub || '',
});
const accounts = compact(partyBalance?.party?.accountsConnection?.edges).map(
(e) => e.node
);
const maxTrade = useMaximumPositionSize({
partyId: pubKey || '',
accounts: accounts,
partyId: keypair?.pub || '',
accounts: partyData?.party?.accounts || [],
marketId: market.id,
settlementAssetId:
market.tradableInstrument.instrument.product.settlementAsset.id,
@@ -100,11 +95,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
order,
});
const estCloseOut = useOrderCloseOut({
order,
market,
partyData: partyBalance,
});
const estCloseOut = useOrderCloseOut({ order, market, partyData });
const slippage = useCalculateSlippage({ marketId: market.id, order });
const [slippageValue, setSlippageValue] = useState(
slippage ? parseFloat(slippage) : 0
@@ -121,7 +112,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
const price = useMemo(() => {
if (slippage && market?.depth?.lastTrade?.price) {
const isLong = order.side === Schema.Side.SIDE_BUY;
const isLong = order.side === Side.SIDE_BUY;
const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus'](
parseFloat(slippage) / 100
);
@@ -137,32 +128,26 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
const notionalSize = useMemo(() => {
if (price) {
const size = new BigNumber(price).multipliedBy(order.size).toNumber();
const size = new BigNumber(price).multipliedBy(orderSize).toNumber();
return addDecimalsFormatNumber(size, market.decimalPlaces);
}
return null;
}, [market.decimalPlaces, order.size, price]);
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
}, [market.decimalPlaces, orderSize, price]);
const fees = useMemo(() => {
if (estMargin?.totalFees && notionalSize) {
const percentage = new BigNumber(estMargin?.totalFees)
if (estMargin?.fees && notionalSize) {
const percentage = new BigNumber(estMargin?.fees)
.dividedBy(notionalSize)
.multipliedBy(100)
.decimalPlaces(2)
.toString();
return `${addDecimalsFormatNumber(
estMargin.totalFees,
assetDecimals
)} (${formatNumber(addDecimal(percentage, assetDecimals), 2)}%)`;
return `${estMargin.fees} (${percentage}%)`;
}
return null;
}, [assetDecimals, estMargin?.totalFees, notionalSize]);
}, [estMargin?.fees, notionalSize]);
const max = useMemo(() => {
return new BigNumber(maxTrade)
@@ -170,16 +155,12 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
.toNumber();
}, [market.positionDecimalPlaces, maxTrade]);
useEffect(() => {
setSlippageValue(slippage ? parseFloat(slippage) : 0);
}, [slippage]);
const onSizeChange = useCallback(
(value: number) => {
const newVal = new BigNumber(value)
.decimalPlaces(market.positionDecimalPlaces)
.toString();
const isValid = validateAmount(step, 'Size')(newVal);
const isValid = validateSize(step)(newVal);
if (isValid !== 'step') {
setValue('size', newVal);
}
@@ -191,7 +172,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
(value: number) => {
if (market?.depth?.lastTrade?.price) {
if (value) {
const isLong = order.side === Schema.Side.SIDE_BUY;
const isLong = order.side === Side.SIDE_BUY;
const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus'](
value / 100
);
@@ -202,11 +183,11 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
setValue('price', bestAskPrice);
if (order.type === Schema.OrderType.TYPE_MARKET) {
setValue('type', Schema.OrderType.TYPE_LIMIT);
if (orderType === OrderType.TYPE_MARKET) {
setValue('type', OrderType.TYPE_LIMIT);
}
} else {
setValue('type', Schema.OrderType.TYPE_MARKET);
setValue('type', OrderType.TYPE_MARKET);
setValue('price', market?.depth?.lastTrade?.price);
}
}
@@ -216,14 +197,13 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
market.decimalPlaces,
market?.depth?.lastTrade?.price,
order.side,
order.type,
setSlippageValue,
orderType,
setValue,
]
);
const onSubmit = useCallback(
(order: OrderSubmissionBody['orderSubmission']) => {
(order: Order) => {
if (transactionStatus !== 'pending') {
submit({
...order,
@@ -264,7 +244,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
)}
/>
),
value: SIDE_NAMES[order.side] || '',
value: SIDE_NAMES[orderSide] || '',
},
{
label: t('Choose Position Size'),
@@ -276,7 +256,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
min={step}
max={max}
onSizeChange={onSizeChange}
size={new BigNumber(order.size).toNumber()}
size={new BigNumber(orderSize).toNumber()}
name="size"
price={formattedPrice || emptyString}
positionDecimalPlaces={market.positionDecimalPlaces}
@@ -285,7 +265,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
.symbol
}
notionalSize={notionalSize || emptyString}
estCloseOut={estCloseOut || emptyString}
estCloseOut={estCloseOut}
fees={fees || emptyString}
estMargin={estMargin?.margin || emptyString}
/>
@@ -295,9 +275,9 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
/>
</>
) : (
t('Loading...')
'loading...'
),
value: order.size,
value: orderSize,
},
{
label: t('Review Trade'),
@@ -315,7 +295,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
isDisabled={isDisabled}
transactionStatus={transactionStatus}
order={order}
estCloseOut={estCloseOut || emptyString}
estCloseOut={estCloseOut}
estMargin={estMargin?.margin || emptyString}
price={formattedPrice || emptyString}
quoteName={
@@ -330,15 +310,9 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
title={getOrderDialogTitle(finalizedOrder?.status)}
intent={getOrderDialogIntent(finalizedOrder?.status)}
icon={getOrderDialogIcon(finalizedOrder?.status)}
content={{
Complete: (
<OrderFeedback
transaction={transaction}
order={finalizedOrder}
/>
),
}}
/>
>
<OrderFeedback transaction={transaction} order={finalizedOrder} />
</Dialog>
</div>
),
disabled: true,
@@ -4,18 +4,19 @@ import {
KeyValueTable,
KeyValueTableRow,
} from '@vegaprotocol/ui-toolkit';
import * as React from 'react';
import classNames from 'classnames';
import { DealTicketEstimates } from '@vegaprotocol/deal-ticket';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import type { Order } from '@vegaprotocol/orders';
import { SIDE_NAMES } from './side-selector';
import SimpleMarketExpires from '../simple-market-list/simple-market-expires';
import { gql, useQuery } from '@apollo/client';
import { Schema } from '@vegaprotocol/types';
import { MarketExpires } from '@vegaprotocol/market-info';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import type {
MarketTags,
MarketTagsVariables,
} from './__generated__/MarketTags';
import { DealTicketEstimates } from './deal-ticket-estimates';
import { Side } from '@vegaprotocol/types';
export const MARKET_TAGS_QUERY = gql`
query MarketTags($marketId: ID!) {
@@ -32,10 +33,10 @@ export const MARKET_TAGS_QUERY = gql`
`;
interface Props {
market: MarketDealTicket;
market: DealTicketMarketFragment;
isDisabled: boolean;
transactionStatus?: string;
order: OrderSubmissionBody['orderSubmission'];
order: Order;
estCloseOut: string;
estMargin: string;
quoteName: string;
@@ -72,10 +73,9 @@ export default ({
<div
className={classNames(
{
'buyButton dark:buyButtonDark':
order.side === Schema.Side.SIDE_BUY,
'buyButton dark:buyButtonDark': order.side === Side.SIDE_BUY,
'sellButton dark:sellButtonDark':
order.side === Schema.Side.SIDE_SELL,
order.side === Side.SIDE_SELL,
},
'px-2 py-1 inline text-ui-small'
)}
@@ -86,7 +86,7 @@ export default ({
<div>
{tagsData?.market?.tradableInstrument.instrument.metadata
.tags && (
<MarketExpires
<SimpleMarketExpires
tags={
tagsData?.market.tradableInstrument.instrument.metadata.tags
}
@@ -2,16 +2,16 @@ import React from 'react';
import classNames from 'classnames';
import { FormGroup } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers';
import { Schema } from '@vegaprotocol/types';
import { Side } from '@vegaprotocol/types';
interface SideSelectorProps {
value: Schema.Side;
onSelect: (side: Schema.Side) => void;
value: Side;
onSelect: (side: Side) => void;
}
export const SIDE_NAMES: Record<Schema.Side, string> = {
[Schema.Side.SIDE_BUY]: t('Long'),
[Schema.Side.SIDE_SELL]: t('Short'),
export const SIDE_NAMES: Record<Side, string> = {
[Side.SIDE_BUY]: t('Long'),
[Side.SIDE_SELL]: t('Short'),
};
export default ({ value, onSelect }: SideSelectorProps) => {
@@ -31,9 +31,9 @@ export default ({ value, onSelect }: SideSelectorProps) => {
className={classNames(
'px-8 py-2',
'buyButton hover:buyButton dark:buyButtonDark dark:hover:buyButtonDark',
{ selected: value === Schema.Side.SIDE_BUY }
{ selected: value === Side.SIDE_BUY }
)}
onClick={() => onSelect(Schema.Side.SIDE_BUY)}
onClick={() => onSelect(Side.SIDE_BUY)}
>
{t('Long')}
</button>
@@ -43,9 +43,9 @@ export default ({ value, onSelect }: SideSelectorProps) => {
className={classNames(
'px-8 py-2',
'sellButton hover:sellButton dark:sellButtonDark dark:hover:sellButtonDark',
{ selected: value === Schema.Side.SIDE_SELL }
{ selected: value === Side.SIDE_SELL }
)}
onClick={() => onSelect(Schema.Side.SIDE_SELL)}
onClick={() => onSelect(Side.SIDE_SELL)}
>
{t('Short')}
</button>
@@ -1,396 +0,0 @@
import * as React from 'react';
import { renderHook } from '@testing-library/react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { MockedProvider } from '@apollo/client/testing';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import {
MarketStateMapping,
Schema as Types,
Schema,
} from '@vegaprotocol/types';
import type { ValidationProps } from './use-order-validation';
import { marketTranslations, useOrderValidation } from './use-order-validation';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import * as DealTicket from '@vegaprotocol/deal-ticket';
jest.mock('@vegaprotocol/wallet');
jest.mock('@vegaprotocol/deal-ticket', () => {
return {
...jest.requireActual('@vegaprotocol/deal-ticket'),
useOrderMarginValidation: jest.fn(),
};
});
type SettlementAsset =
MarketDealTicket['tradableInstrument']['instrument']['product']['settlementAsset'];
const asset: SettlementAsset = {
__typename: 'Asset',
id: 'asset-id',
symbol: 'asset-symbol',
name: 'asset-name',
decimals: 2,
};
const market: MarketDealTicket = {
id: 'market-id',
decimalPlaces: 2,
positionDecimalPlaces: 1,
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
state: Schema.MarketState.STATE_ACTIVE,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
id: 'instrument-id',
name: 'instrument-name',
code: 'instriment-code',
metadata: {
tags: [],
},
product: {
__typename: 'Future',
quoteName: 'quote-name',
settlementAsset: asset,
dataSourceSpecForTradingTermination: {
id: 'dataSource-id',
},
},
},
},
depth: {
__typename: 'MarketDepth',
lastTrade: {
__typename: 'Trade',
price: '100',
},
},
fees: {
__typename: 'Fees',
factors: {
__typename: 'FeeFactors',
makerFee: '1',
infrastructureFee: '2',
liquidityFee: '3',
},
},
data: {
__typename: 'MarketData',
bestBidPrice: '1605489971',
bestOfferPrice: '1606823730',
markPrice: '1606823730',
trigger: Types.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
staticMidPrice: '1606156850',
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
indicativeVolume: '0',
indicativePrice: '0',
bestStaticBidPrice: '1605489971',
bestStaticOfferPrice: '1606823730',
targetStake: '8561302732',
suppliedStake: '727654170336',
auctionStart: null,
auctionEnd: null,
market: { __typename: 'Market', id: 'market-id' },
},
marketTimestamps: {},
};
const defaultWalletContext = {
pubKey: '111111__111111',
pubKeys: [],
sendTx: jest.fn().mockReturnValue(Promise.resolve(null)),
connect: jest.fn(),
disconnect: jest.fn(),
selectPubKey: jest.fn(),
connector: null,
};
const order = {
type: Schema.OrderType.TYPE_MARKET,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
marketId: 'market-id',
side: Schema.Side.SIDE_BUY,
size: '0.1',
};
const defaultOrder = {
market: { ...market },
step: 0.1,
order: {
...order,
},
};
const ERROR = {
KEY_MISSING: 'No public key selected',
KEY_TAINTED: 'Selected public key has been tainted',
MARKET_SUSPENDED: 'Market is currently suspended',
MARKET_INACTIVE: 'Market is no longer active',
MARKET_WAITING: 'Market is not active yet',
MARKET_CONTINUOUS_LIMIT:
'Only limit orders are permitted when market is in auction',
MARKET_CONTINUOUS_TIF:
'Until the auction ends, you can only place GFA, GTT, or GTC limit orders',
FIELD_SIZE_REQ: 'You need to provide a size',
FIELD_SIZE_MIN: `Size cannot be lower than "${defaultOrder.step}"`,
FIELD_PRICE_REQ: 'You need to provide a price',
FIELD_PRICE_MIN: 'The price cannot be negative',
FIELD_PRICE_STEP_NULL: 'Order sizes must be in whole numbers for this market',
FIELD_PRICE_STEP_DECIMAL: `The size field accepts up to ${market.positionDecimalPlaces} decimal places`,
};
function setup(
props?: Partial<ValidationProps>,
context?: Partial<VegaWalletContextShape>
) {
const mockUseVegaWallet = useVegaWallet as jest.Mock;
mockUseVegaWallet.mockReturnValue({ ...defaultWalletContext, context });
return renderHook(() => useOrderValidation({ ...defaultOrder, ...props }), {
wrapper: MockedProvider,
});
}
describe('useOrderValidation', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('Returns empty string when given valid data', () => {
jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({
balance: '0',
margin: '100',
balanceError: false,
});
const { result } = setup();
expect(result.current).toStrictEqual({
isDisabled: false,
message: ``,
section: '',
});
});
it('Returns an error message when no keypair found', () => {
jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({
balance: '0',
margin: '100',
balanceError: false,
});
const { result } = setup(defaultOrder, { pubKey: null });
expect(result.current).toStrictEqual({
isDisabled: false,
message: ``,
section: '',
});
});
it.each`
state
${Schema.MarketState.STATE_SETTLED}
${Schema.MarketState.STATE_REJECTED}
${Schema.MarketState.STATE_TRADING_TERMINATED}
${Schema.MarketState.STATE_CLOSED}
${Schema.MarketState.STATE_CANCELLED}
`(
'Returns an error message for market state when not accepting orders',
({ state }) => {
const { result } = setup({ market: { ...defaultOrder.market, state } });
expect(result.current).toStrictEqual({
isDisabled: true,
message: `This market is ${marketTranslations(
state
)} and not accepting orders`,
section: 'sec-summary',
});
}
);
it.each`
state
${Schema.MarketState.STATE_PENDING}
${Schema.MarketState.STATE_PROPOSED}
`(
'Returns an error message for market state suspended or pending',
({ state }) => {
jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({
balance: '0',
margin: '100',
balanceError: false,
// asset,
});
const { result } = setup({
market: {
...defaultOrder.market,
state,
tradingMode: Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
},
order: {
...order,
type: Schema.OrderType.TYPE_LIMIT,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
},
});
expect(result.current).toStrictEqual({
isDisabled: false,
message: `This market is ${MarketStateMapping[
state as Schema.MarketState
].toLowerCase()} and only accepting liquidity commitment orders`,
section: 'sec-summary',
});
}
);
it.each`
tradingMode | errorMessage
${Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION} | ${ERROR.MARKET_CONTINUOUS_LIMIT}
${Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION} | ${ERROR.MARKET_CONTINUOUS_LIMIT}
${Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION} | ${ERROR.MARKET_CONTINUOUS_LIMIT}
`(
`Returns an error message when trying to submit a non-limit order for a "$tradingMode" market`,
({ tradingMode, errorMessage }) => {
const { result } = setup({
market: { ...defaultOrder.market, tradingMode },
order: {
...order,
type: Schema.OrderType.TYPE_MARKET,
},
});
expect(result.current.isDisabled).toBeTruthy();
expect(result.current.message).toBe(errorMessage);
}
);
it.each`
tradingMode | orderTimeInForce | errorMessage
${Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_FOK} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_FOK} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_FOK} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_IOC} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_IOC} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_IOC} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_GFN} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_GFN} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_GFN} | ${ERROR.MARKET_CONTINUOUS_TIF}
`(
`Returns an error message when submitting a limit order with a "$orderTimeInForce" value to a "$tradingMode" market`,
({ tradingMode, orderTimeInForce, errorMessage }) => {
const { result } = setup({
market: { ...defaultOrder.market, tradingMode },
order: {
...order,
type: Schema.OrderType.TYPE_LIMIT,
timeInForce: orderTimeInForce,
},
});
expect(result.current).toStrictEqual({
isDisabled: true,
message: errorMessage,
section: 'sec-force',
});
}
);
it.each`
fieldName | errorType | section | errorMessage
${`size`} | ${`required`} | ${'sec-size'} | ${ERROR.FIELD_SIZE_REQ}
${`size`} | ${`min`} | ${'sec-size'} | ${ERROR.FIELD_SIZE_MIN}
${`price`} | ${`required`} | ${'sec-price'} | ${ERROR.FIELD_PRICE_REQ}
${`price`} | ${`min`} | ${'sec-price'} | ${ERROR.FIELD_PRICE_MIN}
`(
`Returns an error message when the order $fieldName "$errorType" validation fails`,
({ fieldName, errorType, section, errorMessage }) => {
const { result } = setup({
fieldErrors: { [fieldName]: { type: errorType } },
order: {
...order,
type: Schema.OrderType.TYPE_LIMIT,
},
});
expect(result.current).toStrictEqual({
isDisabled: true,
message: errorMessage,
section,
});
}
);
it('Returns an error message when the order size incorrectly has decimal values', () => {
const { result } = setup({
market: { ...market, positionDecimalPlaces: 0 },
fieldErrors: {
size: { type: `validate`, message: DealTicket.ERROR_SIZE_DECIMAL },
},
});
expect(result.current).toStrictEqual({
isDisabled: true,
message: ERROR.FIELD_PRICE_STEP_NULL,
section: 'sec-size',
});
});
it('Returns an error message when the order size has more decimals than allowed', () => {
const { result } = setup({
fieldErrors: {
size: { type: `validate`, message: DealTicket.ERROR_SIZE_DECIMAL },
},
});
expect(result.current).toStrictEqual({
isDisabled: true,
message: ERROR.FIELD_PRICE_STEP_DECIMAL,
section: 'sec-size',
});
});
it('Returns an error message when the estimated margin is higher than collateral', async () => {
const invalidatedMockValue = {
balance: '100',
margin: '200',
balanceError: true,
};
jest
.spyOn(DealTicket, 'useOrderMarginValidation')
.mockReturnValue(invalidatedMockValue);
const { result } = setup({});
expect(result.current.isDisabled).toBe(false);
const testElement = (
<DealTicket.MarginWarning
margin={invalidatedMockValue.margin}
balance={invalidatedMockValue.balance}
asset={asset}
/>
);
expect((result.current.message as React.ReactElement)?.props).toEqual(
testElement.props
);
expect((result.current.message as React.ReactElement)?.type).toEqual(
testElement.type
);
});
it.each`
state
${Schema.MarketState.STATE_PENDING}
${Schema.MarketState.STATE_PROPOSED}
`(
'Returns error when market state is pending and size is wrong',
({ state }) => {
const { result } = setup({
fieldErrors: {
size: { type: `validate`, message: DealTicket.ERROR_SIZE_DECIMAL },
},
market: {
...market,
state,
},
});
expect(result.current).toStrictEqual({
isDisabled: true,
message: ERROR.FIELD_PRICE_STEP_DECIMAL,
section: 'sec-size',
});
}
);
});
@@ -1,384 +0,0 @@
import type { ReactNode } from 'react';
import type { FieldErrors } from 'react-hook-form';
import { useMemo } from 'react';
import { t, toDecimal } from '@vegaprotocol/react-helpers';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { MarketStateMapping, Schema } from '@vegaprotocol/types';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { Tooltip } from '@vegaprotocol/ui-toolkit';
import {
MarketDataGrid,
compileGridData,
MarginWarning,
isMarketInAuction,
ERROR_SIZE_DECIMAL,
useOrderMarginValidation,
} from '@vegaprotocol/deal-ticket';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
export const DEAL_TICKET_SECTION = {
TYPE: 'sec-type',
SIZE: 'sec-size',
PRICE: 'sec-price',
FORCE: 'sec-force',
EXPIRY: 'sec-expiry',
SUMMARY: 'sec-summary',
};
export const ERROR_EXPIRATION_IN_THE_PAST = 'ERROR_EXPIRATION_IN_THE_PAST';
export type ValidationProps = {
step?: number;
market: MarketDealTicket;
order: OrderSubmissionBody['orderSubmission'];
fieldErrors?: FieldErrors<OrderSubmissionBody['orderSubmission']>;
};
export const marketTranslations = (marketState: Schema.MarketState) => {
switch (marketState) {
case Schema.MarketState.STATE_TRADING_TERMINATED:
return t('terminated');
default:
return t(MarketStateMapping[marketState]).toLowerCase();
}
};
export type DealTicketSection =
| ''
| typeof DEAL_TICKET_SECTION[keyof typeof DEAL_TICKET_SECTION];
export const useOrderValidation = ({
market,
fieldErrors,
order,
}: ValidationProps): {
message: ReactNode | string;
isDisabled: boolean;
section: DealTicketSection;
} => {
const { pubKey } = useVegaWallet();
const minSize = toDecimal(market.positionDecimalPlaces);
const isInvalidOrderMargin = useOrderMarginValidation({ market, order });
const fieldErrorChecking = useMemo<{
message: ReactNode | string;
isDisabled: boolean;
section: DealTicketSection;
} | null>(() => {
if (fieldErrors?.size?.type || fieldErrors?.price?.type) {
if (fieldErrors?.size?.type === 'required') {
return {
isDisabled: true,
message: t('You need to provide a size'),
section: DEAL_TICKET_SECTION.SIZE,
};
}
if (fieldErrors?.size?.type === 'min') {
return {
isDisabled: true,
message: t(`Size cannot be lower than "${minSize}"`),
section: DEAL_TICKET_SECTION.SIZE,
};
}
if (
fieldErrors?.price?.type === 'required' &&
order.type !== Schema.OrderType.TYPE_MARKET
) {
return {
isDisabled: true,
message: t('You need to provide a price'),
section: DEAL_TICKET_SECTION.PRICE,
};
}
if (
fieldErrors?.price?.type === 'min' &&
order.type !== Schema.OrderType.TYPE_MARKET
) {
return {
isDisabled: true,
message: t(`The price cannot be negative`),
section: DEAL_TICKET_SECTION.PRICE,
};
}
if (
fieldErrors?.size?.type === 'validate' &&
fieldErrors?.size?.message === ERROR_SIZE_DECIMAL
) {
if (market.positionDecimalPlaces === 0) {
return {
isDisabled: true,
message: t('Order sizes must be in whole numbers for this market'),
section: DEAL_TICKET_SECTION.SIZE,
};
}
return {
isDisabled: true,
message: t(
`The size field accepts up to ${market.positionDecimalPlaces} decimal places`
),
section: DEAL_TICKET_SECTION.SIZE,
};
}
}
if (
fieldErrors?.expiresAt?.type === 'validate' &&
fieldErrors?.expiresAt.message === ERROR_EXPIRATION_IN_THE_PAST
) {
return {
isDisabled: false,
message: t(
'The expiry date that you have entered appears to be in the past'
),
section: DEAL_TICKET_SECTION.EXPIRY,
};
}
return null;
}, [
fieldErrors?.size?.type,
fieldErrors?.size?.message,
fieldErrors?.price?.type,
fieldErrors?.expiresAt?.type,
fieldErrors?.expiresAt?.message,
order.type,
minSize,
market.positionDecimalPlaces,
]);
const { message, isDisabled, section } = useMemo<{
message: ReactNode | string;
isDisabled: boolean;
section: DealTicketSection;
}>(() => {
if (!pubKey) {
return {
message: t('No public key selected'),
isDisabled: true,
section: DEAL_TICKET_SECTION.SUMMARY,
};
}
if (
[
Schema.MarketState.STATE_SETTLED,
Schema.MarketState.STATE_REJECTED,
Schema.MarketState.STATE_TRADING_TERMINATED,
Schema.MarketState.STATE_CANCELLED,
Schema.MarketState.STATE_CLOSED,
].includes(market.state)
) {
return {
isDisabled: true,
message: t(
`This market is ${marketTranslations(
market.state
)} and not accepting orders`
),
section: DEAL_TICKET_SECTION.SUMMARY,
};
}
if (
[
Schema.MarketState.STATE_PROPOSED,
Schema.MarketState.STATE_PENDING,
].includes(market.state)
) {
if (fieldErrorChecking) {
return fieldErrorChecking;
}
return {
isDisabled: false,
message: t(
`This market is ${marketTranslations(
market.state
)} and only accepting liquidity commitment orders`
),
section: DEAL_TICKET_SECTION.SUMMARY,
};
}
if (isMarketInAuction(market)) {
if (order.type === Schema.OrderType.TYPE_MARKET) {
if (
market.tradingMode ===
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.data?.trigger ===
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
) {
return {
isDisabled: true,
message: (
<span>
{t('This market is in auction until it reaches')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
>
<span>{t('sufficient liquidity')}</span>
</Tooltip>
{'. '}
{t('Only limit orders are permitted when market is in auction')}
</span>
),
section: DEAL_TICKET_SECTION.TYPE,
};
}
if (
market.tradingMode ===
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.data?.trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE
) {
return {
isDisabled: true,
message: (
<span>
{t('This market is in auction due to')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
>
<span>{t('high price volatility')}</span>
</Tooltip>
{'. '}
{t('Only limit orders are permitted when market is in auction')}
</span>
),
section: DEAL_TICKET_SECTION.TYPE,
};
}
return {
isDisabled: true,
message: t(
'Only limit orders are permitted when market is in auction'
),
section: DEAL_TICKET_SECTION.SUMMARY,
};
}
if (
order.type === Schema.OrderType.TYPE_LIMIT &&
[
Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
Schema.OrderTimeInForce.TIME_IN_FORCE_GFN,
].includes(order.timeInForce)
) {
if (
market.tradingMode ===
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.data?.trigger ===
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
) {
return {
isDisabled: true,
message: (
<span>
{t('This market is in auction until it reaches')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
>
<span>{t('sufficient liquidity')}</span>
</Tooltip>
{'. '}
{t(
`Until the auction ends, you can only place GFA, GTT, or GTC limit orders`
)}
</span>
),
section: DEAL_TICKET_SECTION.FORCE,
};
}
if (
market.tradingMode ===
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.data?.trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE
) {
return {
isDisabled: true,
message: (
<span>
{t('This market is in auction due to')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
>
<span>{t('high price volatility')}</span>
</Tooltip>
{'. '}
{t(
`Until the auction ends, you can only place GFA, GTT, or GTC limit orders`
)}
</span>
),
section: DEAL_TICKET_SECTION.FORCE,
};
}
return {
isDisabled: true,
message: t(
`Until the auction ends, you can only place GFA, GTT, or GTC limit orders`
),
section: DEAL_TICKET_SECTION.FORCE,
};
}
}
if (fieldErrorChecking) {
return fieldErrorChecking;
}
if (isInvalidOrderMargin.balanceError) {
return {
isDisabled: false,
message: (
<MarginWarning
margin={isInvalidOrderMargin.margin}
balance={isInvalidOrderMargin.balance}
asset={market.tradableInstrument.instrument.product.settlementAsset}
/>
),
section: DEAL_TICKET_SECTION.PRICE,
};
}
if (
[
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
].includes(market.tradingMode)
) {
return {
isDisabled: false,
message: t(
'Any orders placed now will not trade until the auction ends'
),
section: DEAL_TICKET_SECTION.SUMMARY,
};
}
return {
isDisabled: false,
message: '',
section: '',
};
}, [
pubKey,
market,
fieldErrorChecking,
isInvalidOrderMargin,
order.type,
order.timeInForce,
]);
return { message, isDisabled, section };
};
@@ -0,0 +1,17 @@
query DepositAssets {
assetsConnection {
edges {
node {
id
name
symbol
decimals
source {
... on ERC20 {
contractAddress
}
}
}
}
}
}
@@ -0,0 +1,75 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
import { AssetStatus } from "@vegaprotocol/types";
// ====================================================
// GraphQL query operation: DepositAssets
// ====================================================
export interface DepositAssets_assetsConnection_edges_node_source_BuiltinAsset {
__typename: "BuiltinAsset";
}
export interface DepositAssets_assetsConnection_edges_node_source_ERC20 {
__typename: "ERC20";
/**
* The address of the ERC20 contract
*/
contractAddress: string;
}
export type DepositAssets_assetsConnection_edges_node_source = DepositAssets_assetsConnection_edges_node_source_BuiltinAsset | DepositAssets_assetsConnection_edges_node_source_ERC20;
export interface DepositAssets_assetsConnection_edges_node {
__typename: "Asset";
/**
* The ID of the asset
*/
id: string;
/**
* The full name of the asset (e.g: Great British Pound)
*/
name: string;
/**
* The symbol of the asset (e.g: GBP)
*/
symbol: string;
/**
* The precision of the asset. Should match the decimal precision of the asset on its native chain, e.g: for ERC20 assets, it is often 18
*/
decimals: number;
/**
* The status of the asset in the Vega network
*/
status: AssetStatus;
/**
* The origin source of the asset (e.g: an ERC20 asset)
*/
source: DepositAssets_assetsConnection_edges_node_source;
}
export interface DepositAssets_assetsConnection_edges {
__typename: "AssetEdge";
/**
* The asset information
*/
node: DepositAssets_assetsConnection_edges_node;
}
export interface DepositAssets_assetsConnection {
__typename: "AssetsConnection";
/**
* The assets
*/
edges: (DepositAssets_assetsConnection_edges | null)[] | null;
}
export interface DepositAssets {
/**
* The list of all assets in use in the Vega network or the specified asset if ID is provided
*/
assetsConnection: DepositAssets_assetsConnection | null;
}
@@ -0,0 +1,57 @@
import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type DepositAssetsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type DepositAssetsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string } } } | null> | null } | null };
export const DepositAssetsDocument = gql`
query DepositAssets {
assetsConnection {
edges {
node {
id
name
symbol
decimals
source {
... on ERC20 {
contractAddress
}
}
}
}
}
}
`;
/**
* __useDepositAssetsQuery__
*
* To run a query within a React component, call `useDepositAssetsQuery` and pass it any options that fit your needs.
* When your component renders, `useDepositAssetsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useDepositAssetsQuery({
* variables: {
* },
* });
*/
export function useDepositAssetsQuery(baseOptions?: Apollo.QueryHookOptions<DepositAssetsQuery, DepositAssetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<DepositAssetsQuery, DepositAssetsQueryVariables>(DepositAssetsDocument, options);
}
export function useDepositAssetsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<DepositAssetsQuery, DepositAssetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<DepositAssetsQuery, DepositAssetsQueryVariables>(DepositAssetsDocument, options);
}
export type DepositAssetsQueryHookResult = ReturnType<typeof useDepositAssetsQuery>;
export type DepositAssetsLazyQueryHookResult = ReturnType<typeof useDepositAssetsLazyQuery>;
export type DepositAssetsQueryResult = Apollo.QueryResult<DepositAssetsQuery, DepositAssetsQueryVariables>;
@@ -1,18 +1,61 @@
import { t } from '@vegaprotocol/react-helpers';
import { Button } from '@vegaprotocol/ui-toolkit';
import { DepositDialog, useDepositDialog } from '@vegaprotocol/deposits';
import { gql, useQuery } from '@apollo/client';
import { DepositManager } from '@vegaprotocol/deposits';
import { getEnabledAssets, t } from '@vegaprotocol/react-helpers';
import { Networks, useEnvironment } from '@vegaprotocol/environment';
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { Web3Container } from '@vegaprotocol/web3';
import type { DepositAssets } from './__generated__/DepositAssets';
const DEPOSITS_QUERY = gql`
query DepositAssets {
assetsConnection {
edges {
node {
id
name
symbol
decimals
status
source {
... on ERC20 {
contractAddress
}
}
}
}
}
}
`;
/**
* Fetches data required for the Deposit page
*/
export const DepositContainer = () => {
const openDepositDialog = useDepositDialog((state) => state.open);
const { VEGA_ENV } = useEnvironment();
const { keypair } = useVegaWallet();
const { data, loading, error } = useQuery<DepositAssets>(DEPOSITS_QUERY, {
variables: { partyId: keypair?.pub },
skip: !keypair?.pub,
});
const assets = getEnabledAssets(data);
return (
<div>
<DepositDialog />
<Button size="sm" onClick={() => openDepositDialog()}>
{t('Make deposit')}
</Button>
</div>
<AsyncRenderer<DepositAssets> data={data} loading={loading} error={error}>
{assets.length ? (
<Web3Container>
<DepositManager
assets={assets}
isFaucetable={VEGA_ENV !== Networks.MAINNET}
/>
</Web3Container>
) : (
<Splash>
<p>{t('No assets on this network')}</p>
</Splash>
)}
</AsyncRenderer>
);
};
@@ -1,16 +1,12 @@
import React, { useContext } from 'react';
import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit';
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import Logo from './logo';
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
import LocalContext from '../../context/local-context';
const Header = () => {
const { updateVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
updateVegaWalletDialog: store.updateVegaWalletDialog,
}));
const {
vegaWalletDialog: { setManage },
vegaWalletDialog: { setConnect, setManage },
theme,
toggleTheme,
} = useContext(LocalContext);
@@ -22,7 +18,7 @@ const Header = () => {
<Logo />
<div className="flex items-center gap-2 ml-auto relative z-10">
<VegaWalletConnectButton
setConnectDialog={updateVegaWalletDialog}
setConnectDialog={setConnect}
setManageDialog={setManage}
/>
<ThemeSwitcher theme={theme} onToggle={toggleTheme} className="-my-4" />
@@ -1,10 +1,16 @@
import { useMemo, useRef, useCallback } from 'react';
import { useMemo, useRef } from 'react';
import { useOutletContext } from 'react-router-dom';
import type { AgGridReact } from 'ag-grid-react';
import { PriceCell, useDataProvider } from '@vegaprotocol/react-helpers';
import type { AccountFields } from '@vegaprotocol/accounts';
import { aggregatedAccountsDataProvider, getId } from '@vegaprotocol/accounts';
import type { IGetRowsParams } from 'ag-grid-community';
import type {
AccountFieldsFragment,
AccountEventsSubscription,
} from '@vegaprotocol/accounts';
import {
accountsDataProvider,
accountsManagerUpdate,
getId,
} from '@vegaprotocol/accounts';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import {
AssetDetailsDialog,
@@ -14,51 +20,31 @@ import { NO_DATA_MESSAGE } from '../../../constants';
import { ConsoleLiteGrid } from '../../console-lite-grid';
import { useAccountColumnDefinitions } from '.';
interface AccountObj extends AccountFieldsFragment {
id: string;
}
const AccountsManager = () => {
const { partyId = '' } = useOutletContext<{ partyId: string }>();
const { isOpen, id, setOpen } = useAssetDetailsDialogStore();
const { isOpen, symbol, setOpen } = useAssetDetailsDialogStore();
const gridRef = useRef<AgGridReact | null>(null);
const dataRef = useRef<AccountFields[] | null>(null);
const variables = useMemo(() => ({ partyId }), [partyId]);
const update = useCallback(
({ data }: { data: AccountFields[] | null }) => {
dataRef.current = data;
gridRef.current?.api?.refreshInfiniteCache();
return true;
},
[gridRef]
);
const { data, error, loading } = useDataProvider<AccountFields[], never>({
dataProvider: aggregatedAccountsDataProvider,
update,
variables,
});
const getRows = async ({
successCallback,
startRow,
endRow,
}: IGetRowsParams) => {
const rowsThisBlock = dataRef.current
? dataRef.current.slice(startRow, endRow)
: [];
const lastRow = dataRef.current?.length ?? -1;
successCallback(rowsThisBlock, lastRow);
};
const update = useMemo(() => accountsManagerUpdate(gridRef), []);
const { data, error, loading } = useDataProvider<
AccountFieldsFragment[],
AccountEventsSubscription['accounts']
>({ dataProvider: accountsDataProvider, update, variables });
const { columnDefs, defaultColDef } = useAccountColumnDefinitions();
console.log(data, loading);
return (
<>
<AsyncRenderer
loading={loading}
error={error}
data={data?.length ? data : null}
data={data}
noDataMessage={NO_DATA_MESSAGE}
>
<ConsoleLiteGrid<AccountFields>
rowData={data?.length ? undefined : []}
rowModelType={data?.length ? 'infinite' : 'clientSide'}
ref={gridRef}
datasource={{ getRows }}
<ConsoleLiteGrid<AccountObj>
rowData={data as AccountObj[]}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
components={{ PriceCell }}
@@ -66,7 +52,7 @@ const AccountsManager = () => {
/>
</AsyncRenderer>
<AssetDetailsDialog
assetId={id}
assetSymbol={symbol}
open={isOpen}
onChange={(open) => setOpen(open)}
/>
@@ -1,9 +1,45 @@
import React, { useMemo } from 'react';
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
import type { AccountFields } from '@vegaprotocol/accounts';
import type { SummaryRow } from '@vegaprotocol/react-helpers';
import type { AccountFieldsFragment } from '@vegaprotocol/accounts';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import type { ColDef, GroupCellRendererParams } from 'ag-grid-community';
import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit';
import type {
ColDef,
GroupCellRendererParams,
ValueFormatterParams,
} from 'ag-grid-community';
import type { AccountType } from '@vegaprotocol/types';
import { AccountTypeMapping } from '@vegaprotocol/types';
interface AccountsTableValueFormatterParams extends ValueFormatterParams {
data: AccountFieldsFragment;
}
const comparator = (
valueA: string,
valueB: string,
nodeA: { data: AccountFieldsFragment & SummaryRow },
nodeB: { data: AccountFieldsFragment & SummaryRow },
isInverted: boolean
) => {
if (valueA < valueB) {
return -1;
}
if (valueA > valueB) {
return 1;
}
if (nodeA.data.__summaryRow) {
return isInverted ? -1 : 1;
}
if (nodeB.data.__summaryRow) {
return isInverted ? 1 : -1;
}
return 0;
};
const useAccountColumnDefinitions = () => {
const { open } = useAssetDetailsDialogStore();
@@ -13,16 +49,17 @@ const useAccountColumnDefinitions = () => {
colId: 'account-asset',
headerName: t('Asset'),
field: 'asset.symbol',
comparator,
headerClass: 'uppercase justify-start',
cellClass: 'uppercase flex h-full items-center md:pl-4',
cellRenderer: ({ value, data }: GroupCellRendererParams) =>
cellRenderer: ({ value }: GroupCellRendererParams) =>
value && value.length > 0 ? (
<div className="md:pl-4 grid h-full items-center" title={value}>
<div className="truncate min-w-0">
<button
className="hover:underline"
onClick={() => {
open(data.asset.id);
open(value);
}}
>
{value}
@@ -34,34 +71,28 @@ const useAccountColumnDefinitions = () => {
),
},
{
colId: 'deposited',
headerName: t('Deposited'),
field: 'deposited',
cellRenderer: 'PriceCell',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<AccountFields, 'deposited'>) => {
if (value && data) {
return addDecimalsFormatNumber(value, data.asset.decimals);
}
return '-';
},
colId: 'type',
headerName: t('Type'),
field: 'type',
cellClass: 'uppercase !flex h-full items-center',
valueFormatter: ({ value }: ValueFormatterParams) =>
value ? AccountTypeMapping[value as AccountType] : '-',
},
{
colId: 'used',
headerName: t('Used'),
field: 'used',
colId: 'market',
headerName: t('Market'),
cellClass: 'uppercase !flex h-full items-center',
field: 'market.tradableInstrument.instrument.name',
valueFormatter: "value || '—'",
},
{
colId: 'balance',
headerName: t('Balance'),
field: 'balance',
cellClass: 'uppercase !flex h-full items-center',
cellRenderer: 'PriceCell',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<AccountFields, 'used'>) => {
if (value && data) {
return addDecimalsFormatNumber(value, data.asset.decimals);
}
return '-';
},
valueFormatter: ({ value, data }: AccountsTableValueFormatterParams) =>
addDecimalsFormatNumber(value, data.asset.decimals),
},
];
}, [open]);
@@ -1,7 +1,7 @@
import { useRef } from 'react';
import { useOutletContext } from 'react-router-dom';
import type { AgGridReact } from 'ag-grid-react';
import type { Trade } from '@vegaprotocol/fills';
import type { TradeWithMarket } from '@vegaprotocol/fills';
import { useFillsList } from '@vegaprotocol/fills';
import type { BodyScrollEndEvent, BodyScrollEvent } from 'ag-grid-community';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
@@ -37,7 +37,7 @@ const FillsManager = () => {
data={data?.length ? data : null}
noDataMessage={NO_DATA_MESSAGE}
>
<ConsoleLiteGrid<Trade>
<ConsoleLiteGrid<TradeWithMarket>
ref={gridRef}
rowModelType="infinite"
datasource={{ getRows }}
@@ -1,6 +1,6 @@
import { useMemo } from 'react';
import type { ColDef, ValueFormatterParams } from 'ag-grid-community';
import type { Trade } from '@vegaprotocol/fills';
import type { TradeWithMarket } from '@vegaprotocol/fills';
import classNames from 'classnames';
import {
addDecimal,
@@ -12,7 +12,7 @@ import {
t,
} from '@vegaprotocol/react-helpers';
import BigNumber from 'bignumber.js';
import { Schema } from '@vegaprotocol/types';
import { Side } from '@vegaprotocol/types';
interface Props {
partyId: string;
@@ -34,7 +34,7 @@ const useColumnDefinitions = ({ partyId }: Props) => {
headerClass: 'uppercase',
field: 'size',
width: 100,
cellClass: ({ data }: { data: Trade }) => {
cellClass: ({ data }: { data: TradeWithMarket }) => {
return classNames('!flex h-full items-center justify-center', {
[positiveClassNames]: data?.buyer.id === partyId,
[negativeClassNames]: data?.seller.id,
@@ -118,13 +118,13 @@ const useColumnDefinitions = ({ partyId }: Props) => {
const taker = t('Taker');
const maker = t('Maker');
if (data?.buyer.id === partyId) {
if (value === Schema.Side.SIDE_BUY) {
if (value === Side.SIDE_BUY) {
return taker;
} else {
return maker;
}
} else if (data?.seller.id === partyId) {
if (value === Schema.Side.SIDE_SELL) {
if (value === Side.SIDE_SELL) {
return taker;
} else {
return maker;
@@ -2,7 +2,7 @@ import { useRef, useState } from 'react';
import type { AgGridReact } from 'ag-grid-react';
import type { BodyScrollEndEvent, BodyScrollEvent } from 'ag-grid-community';
import { useOutletContext } from 'react-router-dom';
import type { Order } from '@vegaprotocol/orders';
import type { OrderWithMarket } from '@vegaprotocol/orders';
import {
useOrderCancel,
useOrderListData,
@@ -20,7 +20,7 @@ import useColumnDefinitions from './use-column-definitions';
const OrdersManager = () => {
const { partyId } = useOutletContext<{ partyId: string }>();
const [editOrder, setEditOrder] = useState<Order | null>(null);
const [editOrder, setEditOrder] = useState<OrderWithMarket | null>(null);
const orderCancel = useOrderCancel();
const orderEdit = useOrderEdit(editOrder);
const { columnDefs, defaultColDef } = useColumnDefinitions({
@@ -54,7 +54,7 @@ const OrdersManager = () => {
data={data?.length ? data : null}
noDataMessage={NO_DATA_MESSAGE}
>
<ConsoleLiteGrid<Order>
<ConsoleLiteGrid<OrderWithMarket>
ref={gridRef}
rowModelType={data?.length ? 'infinite' : 'clientSide'}
rowData={data?.length ? undefined : []}
@@ -65,28 +65,22 @@ const OrdersManager = () => {
defaultColDef={defaultColDef}
/>
<orderCancel.Dialog
title={getCancelDialogTitle(orderCancel)}
intent={getCancelDialogIntent(orderCancel)}
content={{
Complete: (
<OrderFeedback
transaction={orderCancel.transaction}
order={orderCancel.cancelledOrder}
/>
),
}}
/>
title={getCancelDialogTitle(orderCancel.cancelledOrder?.status)}
intent={getCancelDialogIntent(orderCancel.cancelledOrder?.status)}
>
<OrderFeedback
transaction={orderCancel.transaction}
order={orderCancel.cancelledOrder}
/>
</orderCancel.Dialog>
<orderEdit.Dialog
title={getEditDialogTitle(orderEdit.updatedOrder?.status)}
content={{
Complete: (
<OrderFeedback
transaction={orderEdit.transaction}
order={orderEdit.updatedOrder}
/>
),
}}
/>
>
<OrderFeedback
transaction={orderEdit.transaction}
order={orderEdit.updatedOrder}
/>
</orderEdit.Dialog>
{editOrder && (
<OrderEditDialog
isOpen={Boolean(editOrder)}
@@ -96,7 +90,7 @@ const OrdersManager = () => {
order={editOrder}
onSubmit={(fields) => {
setEditOrder(null);
orderEdit.edit({ price: fields.limitPrice });
orderEdit.edit({ price: fields.entryPrice });
}}
/>
)}
@@ -11,14 +11,20 @@ import {
positiveClassNames,
t,
} from '@vegaprotocol/react-helpers';
import type { OrderFieldsFragment, Order } from '@vegaprotocol/orders';
import type { OrderCancellationBody } from '@vegaprotocol/wallet';
import type {
Orders_party_ordersConnection_edges_node,
OrderWithMarket,
CancelOrderArgs,
} from '@vegaprotocol/orders';
import { isOrderActive } from '@vegaprotocol/orders';
import {
OrderRejectionReasonMapping,
OrderStatus,
OrderType,
OrderStatusMapping,
OrderTypeMapping,
Schema,
Side,
OrderTimeInForce,
OrderTimeInForceMapping,
} from '@vegaprotocol/types';
@@ -29,9 +35,9 @@ type StatusKey = keyof typeof OrderStatusMapping;
type RejectReasonKey = keyof typeof OrderRejectionReasonMapping;
type OrderTimeKey = keyof typeof OrderTimeInForceMapping;
interface Props {
setEditOrder: (order: Order) => void;
setEditOrder: (order: OrderWithMarket) => void;
orderCancel: {
cancel: (args: OrderCancellationBody['orderCancellation']) => void;
cancel: (args: CancelOrderArgs) => void;
[key: string]: unknown;
};
}
@@ -54,15 +60,21 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
cellClass: 'font-mono !flex h-full items-center',
width: 80,
cellClassRules: {
[positiveClassNames]: ({ data }: { data: OrderFieldsFragment }) =>
data?.side === Schema.Side.SIDE_BUY,
[negativeClassNames]: ({ data }: { data: OrderFieldsFragment }) =>
data?.side === Schema.Side.SIDE_SELL,
[positiveClassNames]: ({
data,
}: {
data: Orders_party_ordersConnection_edges_node;
}) => data?.side === Side.SIDE_BUY,
[negativeClassNames]: ({
data,
}: {
data: Orders_party_ordersConnection_edges_node;
}) => data?.side === Side.SIDE_SELL,
},
valueFormatter: ({ value, data }: ValueFormatterParams) => {
if (value && data && data.market) {
const prefix = data
? data.side === Schema.Side.SIDE_BUY
? data.side === Side.SIDE_BUY
? '+'
: '-'
: '';
@@ -80,8 +92,8 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
valueFormatter: ({
value,
}: ValueFormatterParams & {
value?: OrderFieldsFragment['type'];
}) => OrderTypeMapping[value as Schema.OrderType],
value?: Orders_party_ordersConnection_edges_node['type'];
}) => OrderTypeMapping[value as OrderType],
},
{
colId: 'status',
@@ -94,7 +106,7 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
value?: StatusKey;
}) => {
if (value && data && data.market) {
if (value === Schema.OrderStatus.STATUS_REJECTED) {
if (value === OrderStatus.STATUS_REJECTED) {
return `${OrderStatusMapping[value as StatusKey]}: ${
data.rejectionReason &&
OrderRejectionReasonMapping[
@@ -118,7 +130,7 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
data,
value,
}: ValueFormatterParams & {
value?: OrderFieldsFragment['remaining'];
value?: Orders_party_ordersConnection_edges_node['remaining'];
}) => {
if (value && data && data.market) {
const dps = data.market.positionDecimalPlaces;
@@ -144,13 +156,13 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
value,
data,
}: ValueFormatterParams & {
value?: OrderFieldsFragment['price'];
value?: Orders_party_ordersConnection_edges_node['price'];
}) => {
if (
value === undefined ||
!data ||
!data.market ||
data.type === Schema.OrderType.TYPE_MARKET
data.type === OrderType.TYPE_MARKET
) {
return '-';
}
@@ -169,7 +181,7 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
}) => {
if (value && data?.market) {
if (
value === Schema.OrderTimeInForce.TIME_IN_FORCE_GTT &&
value === OrderTimeInForce.TIME_IN_FORCE_GTT &&
data.expiresAt
) {
const expiry = getDateTimeFormat().format(
@@ -191,7 +203,7 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
valueFormatter: ({
value,
}: ValueFormatterParams & {
value?: OrderFieldsFragment['createdAt'];
value?: Orders_party_ordersConnection_edges_node['createdAt'];
}) => {
return value ? getDateTimeFormat().format(new Date(value)) : value;
},
@@ -203,7 +215,7 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
valueFormatter: ({
value,
}: ValueFormatterParams & {
value?: OrderFieldsFragment['updatedAt'];
value?: Orders_party_ordersConnection_edges_node['updatedAt'];
}) => {
return value ? getDateTimeFormat().format(new Date(value)) : '-';
},
@@ -6,11 +6,11 @@ import { HorizontalMenu } from '../horizontal-menu';
import * as constants from './constants';
export const Portfolio = () => {
const { pubKey } = useVegaWallet();
const { keypair } = useVegaWallet();
const { pathname } = useLocation();
const module = pathname.split('/portfolio/')?.[1] ?? '';
const outlet = useOutlet({ partyId: pubKey || '' });
if (!pubKey) {
const outlet = useOutlet({ partyId: keypair?.pub || '' });
if (!keypair) {
return (
<section className="xl:w-1/2">
<ConnectWallet />
@@ -0,0 +1,58 @@
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { useRef } from 'react';
import type { AgGridReact } from 'ag-grid-react';
import type { Position } from '@vegaprotocol/positions';
import { PriceFlashCell, t } from '@vegaprotocol/react-helpers';
import { AssetBalance } from '@vegaprotocol/accounts';
import { usePositionsData } from '@vegaprotocol/positions';
import { ConsoleLiteGrid } from '../../console-lite-grid';
import useColumnDefinitions from './use-column-definitions';
interface Props {
partyId: string;
assetSymbol: string;
}
const getRowId = ({ data }: { data: Position }) => data.marketId;
const PositionsAsset = ({ partyId, assetSymbol }: Props) => {
const gridRef = useRef<AgGridReact | null>(null);
const { data, error, loading, getRows } = usePositionsData(
partyId,
gridRef,
assetSymbol
);
const { columnDefs, defaultColDef } = useColumnDefinitions();
return (
<AsyncRenderer loading={loading} error={error} data={data}>
<div
data-testid={`positions-asset-${assetSymbol}`}
className="flex justify-between items-center px-4 pt-3 pb-1"
>
<h4>
{assetSymbol} {t('markets')}
</h4>
<div className="text-sm text-neutral-500 dark:text-neutral-300">
{assetSymbol} {t('balance')}:
<span data-testid="balance" className="pl-1 font-mono">
<AssetBalance partyId={partyId} assetSymbol={assetSymbol} />
</span>
</div>
</div>
<ConsoleLiteGrid<Position & { id: undefined }>
ref={gridRef}
domLayout="autoHeight"
classNamesParam="h-auto"
columnDefs={columnDefs}
defaultColDef={defaultColDef}
getRowId={getRowId}
rowModelType={data?.length ? 'infinite' : 'clientSide'}
rowData={data?.length ? undefined : []}
datasource={{ getRows }}
components={{ PriceFlashCell }}
/>
</AsyncRenderer>
);
};
export default PositionsAsset;
@@ -1,37 +1,26 @@
import { useOutletContext } from 'react-router-dom';
import { PriceFlashCell } from '@vegaprotocol/react-helpers';
import { usePositionsData, getRowId } from '@vegaprotocol/positions';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { ConsoleLiteGrid } from '../../console-lite-grid';
import { useRef } from 'react';
import type { AgGridReact } from 'ag-grid-react';
import type { Position } from '@vegaprotocol/positions';
import { NO_DATA_MESSAGE } from '../../../constants';
import useColumnDefinitions from './use-column-definitions';
import { t } from '@vegaprotocol/react-helpers';
import { usePositionsAssets } from '@vegaprotocol/positions';
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
import PositionsAsset from './positions-asset';
const Positions = () => {
const gridRef = useRef<AgGridReact | null>(null);
const { partyId } = useOutletContext<{ partyId: string }>();
const { data, error, loading } = usePositionsData(partyId, gridRef);
const { columnDefs, defaultColDef } = useColumnDefinitions();
const { data, error, loading, assetSymbols } = usePositionsAssets(partyId);
return (
<AsyncRenderer
loading={loading}
error={error}
data={data?.length ? data : null}
noDataMessage={NO_DATA_MESSAGE}
>
<ConsoleLiteGrid<Position>
ref={gridRef}
domLayout="autoHeight"
classNamesParam="h-auto"
columnDefs={columnDefs}
defaultColDef={defaultColDef}
getRowId={getRowId}
rowData={data || undefined}
components={{ PriceFlashCell }}
/>
<AsyncRenderer loading={loading} error={error} data={data}>
{assetSymbols && assetSymbols.length > 0 && (
<div className="w-full, h-max">
{assetSymbols?.map((assetSymbol) => (
<PositionsAsset
key={assetSymbol}
partyId={partyId}
assetSymbol={assetSymbol}
/>
))}
</div>
)}
{assetSymbols?.length === 0 && <Splash>{t('No data to display')}</Splash>}
</AsyncRenderer>
);
};
@@ -7,8 +7,11 @@ import {
signedNumberCssClassRules,
t,
} from '@vegaprotocol/react-helpers';
import type { Position } from '@vegaprotocol/positions';
import { AmountCell } from '@vegaprotocol/positions';
import type {
PositionsTableValueFormatterParams,
Position,
} from '@vegaprotocol/positions';
import { AmountCell, ProgressBarCell } from '@vegaprotocol/positions';
import type {
CellRendererSelectorResult,
ICellRendererParams,
@@ -16,9 +19,8 @@ import type {
GroupCellRendererParams,
ColDef,
} from 'ag-grid-community';
import { Schema } from '@vegaprotocol/types';
import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit';
import { Intent, ProgressBarCell } from '@vegaprotocol/ui-toolkit';
import { MarketTradingMode } from '@vegaprotocol/types';
import { Intent } from '@vegaprotocol/ui-toolkit';
const EmptyCell = () => '';
@@ -75,7 +77,9 @@ const useColumnDefinitions = () => {
value,
data,
node,
}: VegaValueFormatterParams<Position, 'openVolume'>) => {
}: PositionsTableValueFormatterParams & {
value: Position['openVolume'];
}) => {
let ret;
if (value && data) {
ret = node?.rowPinned
@@ -103,13 +107,15 @@ const useColumnDefinitions = () => {
value,
data,
node,
}: VegaValueFormatterParams<Position, 'markPrice'>) => {
}: PositionsTableValueFormatterParams & {
value: Position['markPrice'];
}) => {
if (
data &&
value &&
node?.rowPinned &&
data.marketTradingMode ===
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION
MarketTradingMode.TRADING_MODE_OPENING_AUCTION
) {
return addDecimalsFormatNumber(
value.toString(),
@@ -180,8 +186,9 @@ const useColumnDefinitions = () => {
valueFormatter: ({
value,
node,
}: VegaValueFormatterParams<Position, 'currentLeverage'>) =>
value === undefined ? '' : formatNumber(value.toString(), 1),
}: PositionsTableValueFormatterParams & {
value: Position['currentLeverage'];
}) => (value === undefined ? '' : formatNumber(value.toString(), 1)),
},
{
colId: 'marginallocated',
@@ -222,8 +229,10 @@ const useColumnDefinitions = () => {
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<Position, 'realisedPNL'>) =>
value === undefined || data === undefined
}: PositionsTableValueFormatterParams & {
value: Position['realisedPNL'];
}) =>
value === undefined
? ''
: addDecimalsFormatNumber(value.toString(), data.decimals),
cellRenderer: 'PriceFlashCell',
@@ -240,8 +249,10 @@ const useColumnDefinitions = () => {
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<Position, 'unrealisedPNL'>) =>
value === undefined || data === undefined
}: PositionsTableValueFormatterParams & {
value: Position['unrealisedPNL'];
}) =>
value === undefined
? ''
: addDecimalsFormatNumber(value.toString(), data.decimals),
cellRenderer: 'PriceFlashCell',
@@ -255,7 +266,9 @@ const useColumnDefinitions = () => {
type: 'rightAligned',
valueFormatter: ({
value,
}: VegaValueFormatterParams<Position, 'updatedAt'>) => {
}: PositionsTableValueFormatterParams & {
value: Position['updatedAt'];
}) => {
if (!value) {
return '';
}
@@ -1,24 +1,21 @@
import { t } from '@vegaprotocol/react-helpers';
import { themelite as theme } from '@vegaprotocol/tailwindcss-config';
import { Schema } from '@vegaprotocol/types';
import { MarketState } from '@vegaprotocol/types';
import colors from 'tailwindcss/colors';
import type { Market } from '@vegaprotocol/market-list';
import { IS_MARKET_TRADABLE } from '../../constants';
export const STATES_FILTER = [
{ value: 'all', text: t('All') },
{ value: Schema.MarketState.STATE_ACTIVE, text: t('Active') },
{ value: Schema.MarketState.STATE_CANCELLED, text: t('Cancelled') },
{ value: Schema.MarketState.STATE_CLOSED, text: t('Closed') },
{ value: Schema.MarketState.STATE_PENDING, text: t('Pending') },
{ value: Schema.MarketState.STATE_PROPOSED, text: t('Proposed') },
{ value: Schema.MarketState.STATE_REJECTED, text: t('Rejected') },
{ value: Schema.MarketState.STATE_SETTLED, text: t('Settled') },
{ value: Schema.MarketState.STATE_SUSPENDED, text: t('Suspended') },
{
value: Schema.MarketState.STATE_TRADING_TERMINATED,
text: t('TradingTerminated'),
},
{ value: MarketState.STATE_ACTIVE, text: t('Active') },
{ value: MarketState.STATE_CANCELLED, text: t('Cancelled') },
{ value: MarketState.STATE_CLOSED, text: t('Closed') },
{ value: MarketState.STATE_PENDING, text: t('Pending') },
{ value: MarketState.STATE_PROPOSED, text: t('Proposed') },
{ value: MarketState.STATE_REJECTED, text: t('Rejected') },
{ value: MarketState.STATE_SETTLED, text: t('Settled') },
{ value: MarketState.STATE_SUSPENDED, text: t('Suspended') },
{ value: MarketState.STATE_TRADING_TERMINATED, text: t('TradingTerminated') },
];
export const agGridLightVariables = `
@@ -1,22 +1,8 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { render, screen } from '@testing-library/react';
import SimpleMarketExpires from './simple-market-expires';
import { MarketExpires } from './market-expires';
jest.mock('@vegaprotocol/react-helpers', () => ({
t: jest.fn().mockImplementation((text) => text),
getDateTimeFormat: () =>
Intl.DateTimeFormat('en-GB', {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
}),
}));
describe('MarketExpires', () => {
describe('SimpleMarketExpires', () => {
describe('should properly parse different tags', () => {
it('settlement:date', () => {
const tags = [
@@ -26,8 +12,8 @@ describe('MarketExpires', () => {
'settlement:notadate',
'settlement:20220525T1200',
];
render(<MarketExpires tags={tags} />);
expect(screen.getByText('25/05/2022, 12:00:00')).toBeInTheDocument();
render(<SimpleMarketExpires tags={tags} />);
expect(screen.getByText('May 25')).toBeInTheDocument();
});
it('settlement-date:date', () => {
@@ -36,8 +22,8 @@ describe('MarketExpires', () => {
'settlement:20220525T1200',
'settlement-date:2022-04-25T1200',
];
render(<MarketExpires tags={tags} />);
expect(screen.getByText('25/04/2022, 12:00:00')).toBeInTheDocument();
render(<SimpleMarketExpires tags={tags} />);
expect(screen.getByText('Apr 25')).toBeInTheDocument();
});
it('last one proper tag should matter', () => {
@@ -46,8 +32,8 @@ describe('MarketExpires', () => {
'settlement-date:20220525T1200',
'settlement-expiry-date:2022-03-25T12:00:00',
];
render(<MarketExpires tags={tags} />);
expect(screen.getByText('25/03/2022, 12:00:00')).toBeInTheDocument();
render(<SimpleMarketExpires tags={tags} />);
expect(screen.getByText('Mar 25')).toBeInTheDocument();
});
it('when no proper tag nor date should be null', () => {
@@ -56,7 +42,7 @@ describe('MarketExpires', () => {
'settlemenz:20220525T1200',
'settlemenx-date:20220425T1200',
];
const { container } = render(<MarketExpires tags={tags} />);
const { container } = render(<SimpleMarketExpires tags={tags} />);
expect(container.firstChild).toBeNull();
});
});
@@ -0,0 +1,34 @@
import React from 'react';
import { format, isValid, parseISO } from 'date-fns';
import { EXPIRE_DATE_FORMAT } from '../../constants';
const SimpleMarketExpires = ({
tags,
}: {
tags: ReadonlyArray<string> | null;
}) => {
if (tags) {
const dateFound = tags.reduce<Date | null>((agg, tag) => {
const parsed = parseISO(
(tag.match(/^settlement.*:/) &&
tag
.split(':')
.filter((item, i) => i)
.join(':')) as string
);
if (isValid(parsed)) {
agg = parsed;
}
return agg;
}, null);
return dateFound ? (
<div className="p-2 text-ui-small border border-pink text-pink inline-block">{`${format(
dateFound as Date,
EXPIRE_DATE_FORMAT
)}`}</div>
) : null;
}
return null;
};
export default SimpleMarketExpires;
@@ -9,7 +9,7 @@ import {
} from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import { BrowserRouter } from 'react-router-dom';
import { Schema } from '@vegaprotocol/types';
import { MarketState } from '@vegaprotocol/types';
import type { Market } from '@vegaprotocol/market-list';
import SimpleMarketList from './simple-market-list';
@@ -26,7 +26,7 @@ jest.mock('./simple-market-percent-change', () => jest.fn());
let marketsMock = [
{
id: 'MARKET_A',
state: Schema.MarketState.STATE_ACTIVE,
state: MarketState.STATE_ACTIVE,
tradableInstrument: {
instrument: {
product: {
@@ -42,7 +42,7 @@ let marketsMock = [
},
{
id: 'MARKET_B',
state: Schema.MarketState.STATE_ACTIVE,
state: MarketState.STATE_ACTIVE,
tradableInstrument: {
instrument: {
product: {
@@ -58,17 +58,21 @@ let marketsMock = [
},
] as unknown as Market[];
const LIB = '@vegaprotocol/react-helpers';
const useDataProvider = () => {
const LIB = '@vegaprotocol/market-list';
const useMarketList = () => {
return {
data: marketsMock,
data: {
markets: marketsMock,
marketsData: [],
marketsCandles: [],
},
loading: false,
error: false,
};
};
jest.mock(LIB, () => ({
...jest.requireActual(LIB),
useDataProvider: jest.fn(() => useDataProvider()),
useMarketList: jest.fn(() => useMarketList()),
}));
const mockIsTradable = jest.fn((_arg) => true);
@@ -121,7 +125,7 @@ describe('SimpleMarketList', () => {
expect(mockIsTradable).toHaveBeenCalledWith(
expect.objectContaining({
id: marketsMock[0].id,
state: Schema.MarketState.STATE_ACTIVE,
state: MarketState.STATE_ACTIVE,
})
);
expect(mockedNavigate).toHaveBeenCalledWith(
@@ -1,20 +1,16 @@
import { useCallback, useEffect, useRef, useMemo } from 'react';
import React, { useCallback, useEffect, useRef } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import type { AgGridReact } from 'ag-grid-react';
import {
useScreenDimensions,
useDataProvider,
useYesterday,
} from '@vegaprotocol/react-helpers';
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import type { MarketState } from '@vegaprotocol/types';
import useMarketsFilterData from './use-markets-filter-data';
import useColumnDefinitions from './use-column-definitions';
import SimpleMarketToolbar from './simple-market-toolbar';
import { IS_MARKET_TRADABLE } from '../../constants';
import { ConsoleLiteGrid } from '../console-lite-grid';
import type { Market } from '@vegaprotocol/market-list';
import { Schema } from '@vegaprotocol/types';
import { marketsWithCandlesProvider } from '@vegaprotocol/market-list';
import type { Market, MarketsListData } from '@vegaprotocol/market-list';
import { useMarketList } from '@vegaprotocol/market-list';
export type MarketWithPercentChange = Market & {
percentChange?: number | '-';
@@ -30,30 +26,19 @@ const SimpleMarketList = () => {
const { isMobile } = useScreenDimensions();
const navigate = useNavigate();
const params = useParams<RouterParams>();
const statusesRef = useRef<Record<string, Schema.MarketState | ''>>({});
const statusesRef = useRef<Record<string, MarketState | ''>>({});
const gridRef = useRef<AgGridReact | null>(null);
const yesterday = useYesterday();
const variables = useMemo(() => {
return {
since: new Date(yesterday).toISOString(),
interval: Schema.Interval.INTERVAL_I1H,
};
}, [yesterday]);
const { data, error, loading } = useDataProvider({
dataProvider: marketsWithCandlesProvider,
variables,
skipUpdates: true,
});
const localData = useMarketsFilterData(data, params);
const { data, error, loading } = useMarketList();
const localData = useMarketsFilterData(data as MarketsListData, params);
const handleOnGridReady = useCallback(() => {
gridRef.current?.api?.sizeColumnsToFit();
}, [gridRef]);
useEffect(() => {
const statuses: Record<string, Schema.MarketState | ''> = {};
data?.forEach((market) => {
const statuses: Record<string, MarketState | ''> = {};
data?.markets?.forEach((market) => {
statuses[market.id] = market.state || '';
});
statusesRef.current = statuses;
@@ -77,7 +62,7 @@ const SimpleMarketList = () => {
return (
<div className="h-full p-4 md:p-6 grid grid-rows-[min-content,1fr]">
<SimpleMarketToolbar data={data || []} />
<SimpleMarketToolbar data={data?.markets || []} />
<AsyncRenderer loading={loading} error={error} data={localData}>
<ConsoleLiteGrid<MarketWithPercentChange>
classNamesParam="mb-32 min-h-[300px]"
@@ -85,7 +70,6 @@ const SimpleMarketList = () => {
rowData={localData}
defaultColDef={defaultColDef}
handleRowClicked={handleRowClicked}
getRowId={({ data }) => data.id}
/>
</AsyncRenderer>
</div>
@@ -1,10 +1,10 @@
import { useEffect, useState } from 'react';
import classNames from 'classnames';
import { InView } from 'react-intersection-observer';
import { useDataProvider, useYesterday } from '@vegaprotocol/react-helpers';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import type { Candle } from '@vegaprotocol/market-list';
import { marketCandlesProvider } from '@vegaprotocol/market-list';
import { Schema } from '@vegaprotocol/types';
import { Interval } from '@vegaprotocol/types';
interface Props {
candles: (Candle | null)[] | null;
@@ -68,13 +68,13 @@ const SimpleMarketPercentChangeWrapper = (props: Props) => {
};
const SimpleMarketPercentChange = ({ candles, marketId, setValue }: Props) => {
const yesterday = useYesterday();
const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600;
const { data } = useDataProvider({
dataProvider: marketCandlesProvider,
variables: {
marketId,
interval: Schema.Interval.INTERVAL_I1D,
since: new Date(yesterday).toISOString(),
interval: Interval.INTERVAL_I1D,
since: new Date(yesterday * 1000).toISOString(),
},
});
@@ -1,13 +1,13 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { Schema } from '@vegaprotocol/types';
import { MarketState } from '@vegaprotocol/types';
import MarketNameRenderer from './simple-market-renderer';
import type { Market } from '@vegaprotocol/market-list';
describe('SimpleMarketRenderer', () => {
const market = {
id: 'MARKET_A',
state: Schema.MarketState.STATE_ACTIVE,
state: MarketState.STATE_ACTIVE,
tradableInstrument: {
instrument: {
code: 'MARKET_A_CODE',
@@ -1,6 +1,6 @@
import classNames from 'classnames';
import SimpleMarketExpires from './simple-market-expires';
import type { Market } from '@vegaprotocol/market-list';
import { MarketExpires } from '@vegaprotocol/market-info';
interface Props {
market: Market;
@@ -19,7 +19,7 @@ const MarketNameRenderer = ({ market, isMobile }: Props) => {
{isMobile
? market.tradableInstrument.instrument.code
: market.tradableInstrument.instrument.name}{' '}
<MarketExpires
<SimpleMarketExpires
tags={market.tradableInstrument.instrument.metadata.tags}
/>
</div>
@@ -14,9 +14,9 @@ import {
getAllByText,
} from '@testing-library/react';
import { MockedProvider } from '@apollo/react-testing';
import { Schema } from '@vegaprotocol/types';
import type { Market } from '@vegaprotocol/market-list';
import { MarketState } from '@vegaprotocol/types';
import SimpleMarketToolbar from './simple-market-toolbar';
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
import { markets as filterData } from './mocks/market-filters.json';
const mockedNavigate = jest.fn();
@@ -35,23 +35,35 @@ describe('SimpleMarketToolbar', () => {
const routes = useRoutes([
{
path: '/',
element: <SimpleMarketToolbar data={filterData as Market[]} />,
element: (
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
),
},
{
path: 'markets',
children: [
{
path: `:state`,
element: <SimpleMarketToolbar data={filterData as Market[]} />,
element: (
<SimpleMarketToolbar
data={filterData as SimpleMarkets_markets[]}
/>
),
children: [
{
path: `:product`,
element: <SimpleMarketToolbar data={filterData as Market[]} />,
element: (
<SimpleMarketToolbar
data={filterData as SimpleMarkets_markets[]}
/>
),
children: [
{
path: `:asset`,
element: (
<SimpleMarketToolbar data={filterData as Market[]} />
<SimpleMarketToolbar
data={filterData as SimpleMarkets_markets[]}
/>
),
},
],
@@ -59,7 +71,9 @@ describe('SimpleMarketToolbar', () => {
],
},
],
element: <SimpleMarketToolbar data={filterData as Market[]} />,
element: (
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
),
},
]);
const location = useLocation();
@@ -113,7 +127,7 @@ describe('SimpleMarketToolbar', () => {
await waitFor(() => {
expect(screen.getByTestId('location-display')).toHaveTextContent(
`/markets/${Schema.MarketState.STATE_ACTIVE}/Future`
`/markets/${MarketState.STATE_ACTIVE}/Future`
);
});
@@ -124,7 +138,7 @@ describe('SimpleMarketToolbar', () => {
);
await waitFor(() => {
expect(screen.getByTestId('location-display')).toHaveTextContent(
`/markets/${Schema.MarketState.STATE_ACTIVE}/Future/tEURO`
`/markets/${MarketState.STATE_ACTIVE}/Future/tEURO`
);
});
@@ -139,7 +153,7 @@ describe('SimpleMarketToolbar', () => {
});
await waitFor(() => {
expect(mockedNavigate).toHaveBeenCalledWith(
`/markets/${Schema.MarketState.STATE_PENDING}/Future/tEURO`
`/markets/${MarketState.STATE_PENDING}/Future/tEURO`
);
});
});
@@ -152,7 +166,7 @@ describe('SimpleMarketToolbar', () => {
}));
render(
<MockedProvider mocks={[]} addTypename={false}>
<SimpleMarketToolbar data={filterData as Market[]} />
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
</MockedProvider>,
{ wrapper: BrowserRouter }
);
@@ -165,7 +179,7 @@ describe('SimpleMarketToolbar', () => {
fireEvent.click(suspended);
expect(mockedNavigate).toHaveBeenCalledWith(
`/markets/${Schema.MarketState.STATE_SUSPENDED}/product1/asset1`
`/markets/${MarketState.STATE_SUSPENDED}/product1/asset1`
);
});
@@ -173,7 +187,7 @@ describe('SimpleMarketToolbar', () => {
(useParams as jest.Mock).mockImplementation(() => ({}));
render(
<MockedProvider mocks={[]} addTypename={false}>
<SimpleMarketToolbar data={filterData as Market[]} />
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
</MockedProvider>,
{ wrapper: BrowserRouter }
);
@@ -186,7 +200,7 @@ describe('SimpleMarketToolbar', () => {
fireEvent.click(closed);
expect(mockedNavigate).toHaveBeenCalledWith(
`/markets/${Schema.MarketState.STATE_CLOSED}`
`/markets/${MarketState.STATE_CLOSED}`
);
});
@@ -197,7 +211,7 @@ describe('SimpleMarketToolbar', () => {
}));
render(
<MockedProvider mocks={[]} addTypename={false}>
<SimpleMarketToolbar data={filterData as Market[]} />
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
</MockedProvider>,
{ wrapper: BrowserRouter }
);
@@ -1,4 +1,4 @@
import { useCallback, useMemo, useState } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import classNames from 'classnames';
import { useNavigate, useParams, Link } from 'react-router-dom';
import {
@@ -13,21 +13,21 @@ import {
DropdownMenuItemIndicator,
Icon,
} from '@vegaprotocol/ui-toolkit';
import { Schema } from '@vegaprotocol/types';
import type { Market } from '@vegaprotocol/market-list';
import { MarketState } from '@vegaprotocol/types';
import useMarketFiltersData from '../../hooks/use-markets-filter';
import type { Markets_marketsConnection_edges_node } from '@vegaprotocol/market-list';
import { HorizontalMenu } from '../horizontal-menu';
import type { HorizontalMenuItem } from '../horizontal-menu';
import * as constants from './constants';
import { useMarketFilters } from '../../hooks/use-markets-filter';
interface Props {
data: Market[];
data: Markets_marketsConnection_edges_node[];
}
const SimpleMarketToolbar = ({ data }: Props) => {
const navigate = useNavigate();
const params = useParams();
const { products, assetsPerProduct } = useMarketFilters(data);
const { products, assetsPerProduct } = useMarketFiltersData(data);
const [isOpen, setOpen] = useState(false);
const onStateChange = useCallback(
@@ -36,7 +36,7 @@ const SimpleMarketToolbar = ({ data }: Props) => {
params.asset && params.asset !== 'all' ? `/${params.asset}` : '';
const product = params.product ? `/${params.product}` : '';
const state =
activeState !== Schema.MarketState.STATE_ACTIVE || product
activeState !== MarketState.STATE_ACTIVE || product
? `/${activeState}`
: '';
navigate(`/markets${state}${product}${asset}`);
@@ -45,8 +45,8 @@ const SimpleMarketToolbar = ({ data }: Props) => {
);
const productItems = useMemo(() => {
const currentState = params.state || Schema.MarketState.STATE_ACTIVE;
const noStateSkip = currentState !== Schema.MarketState.STATE_ACTIVE;
const currentState = params.state || MarketState.STATE_ACTIVE;
const noStateSkip = currentState !== MarketState.STATE_ACTIVE;
const items: HorizontalMenuItem[] = [
{
...constants.ALL_PRODUCTS_ITEM,
@@ -83,8 +83,7 @@ const SimpleMarketToolbar = ({ data }: Props) => {
{constants.STATES_FILTER.find(
(state) =>
state.value === params.state ||
(!params.state &&
state.value === Schema.MarketState.STATE_ACTIVE)
(!params.state && state.value === MarketState.STATE_ACTIVE)
)?.text || params.state}
<Icon
name={IconNames.ARROW_DOWN}
@@ -104,7 +103,7 @@ const SimpleMarketToolbar = ({ data }: Props) => {
key={value}
checked={
value === params.state ||
(!params.state && value === Schema.MarketState.STATE_ACTIVE)
(!params.state && value === MarketState.STATE_ACTIVE)
}
onCheckedChange={() => onStateChange(value)}
>
@@ -7,7 +7,7 @@ import { Icon } from '@vegaprotocol/ui-toolkit';
import type { ValueSetterParams } from 'ag-grid-community';
import { IconNames } from '@blueprintjs/icons';
import { IS_MARKET_TRADABLE, MARKET_STATES_MAP } from '../../constants';
import type { MarketWithCandles as Market } from '@vegaprotocol/market-list';
import type { Candle, Market } from '@vegaprotocol/market-list';
interface Props {
isMobile: boolean;
@@ -69,16 +69,15 @@ const useColumnDefinitions = ({ isMobile }: Props) => {
data,
setValue,
}: {
data: Market;
data: { id: string; candles: Candle[] };
setValue: (arg: unknown) => void;
}) =>
data.candles && (
<SimpleMarketPercentChange
candles={data.candles}
marketId={data.id}
setValue={setValue}
/>
),
}) => (
<SimpleMarketPercentChange
candles={data.candles}
marketId={data.id}
setValue={setValue}
/>
),
comparator: (valueA: number | '-', valueB: number | '-') => {
if (valueA === valueB) return 0;
if (valueA === '-') {
@@ -1,15 +1,12 @@
import { useMemo } from 'react';
import { Schema } from '@vegaprotocol/types';
import type { MarketWithCandles } from '@vegaprotocol/market-list';
import { MarketState } from '@vegaprotocol/types';
import type { MarketsListData } from '@vegaprotocol/market-list';
import type { RouterParams } from './simple-market-list';
const useMarketsFilterData = (
data: MarketWithCandles[] | null,
params: RouterParams
) => {
const useMarketsFilterData = (data: MarketsListData, params: RouterParams) => {
return useMemo(() => {
return (
data?.filter((item) => {
const markets =
data?.markets?.filter((item) => {
if (
params.product &&
params.product !==
@@ -30,14 +27,26 @@ const useMarketsFilterData = (
? ''
: params.state
? params.state
: Schema.MarketState.STATE_ACTIVE;
: MarketState.STATE_ACTIVE;
if (state && state !== item.state) {
return false;
}
return true;
}) || []
);
}, [data, params.product, params.asset, params.state]);
}) || [];
return markets.map((market) => ({
...market,
candles: (data?.marketsCandles || [])
.filter((c) => c.marketId === market.id)
.map((c) => c.candles),
}));
}, [
data?.marketsCandles,
data?.markets,
params.product,
params.asset,
params.state,
]);
};
export default useMarketsFilterData;

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