Compare commits

..
Author SHA1 Message Date
Botond 01320f9748 fix: format 2022-08-26 19:39:10 +02:00
Botond 91cdd434b6 fix: imports 2022-08-26 19:38:15 +02:00
Botond ed8b053d7b fix: format 2022-08-26 18:55:11 +02:00
Botond 8ae5b66824 feat: add network config override 2022-08-26 18:54:33 +02:00
Botond 563021aa0b feat: add network update 2022-08-26 15:52:17 +02:00
Botond 13c35a5f65 chore: merge source 2022-08-26 13:38:26 +02:00
Botond ee1223c9f6 fix: add missing utils 2022-08-26 13:37:50 +02:00
Botond c368d0b546 chore: merge source 2022-08-26 13:33:52 +02:00
Botond ad06481408 fix: format 2022-08-26 13:33:19 +02:00
Botond a928669fc7 feat: merge source 2022-08-26 13:32:50 +02:00
Botond 69d3313f90 fix: format 2022-08-25 18:08:52 +02:00
Botond 04c1d68333 feat: add type update script 2022-08-25 17:47:40 +02:00
2176 changed files with 56152 additions and 130994 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
apps/**/dist/*
apps/**/node_modules/*
dist/*
node_modules/*
tmp/*
.dockerignore
dockerfiles
Dockerfile
+3 -3
View File
@@ -51,7 +51,8 @@
"ul": ["list"],
"ol": ["list"]
}
]
],
"curly": "warn"
}
},
{
@@ -74,8 +75,7 @@
"prefer": "type-imports",
"disallowTypeAnnotations": true
}
],
"curly": ["error", "multi-line"]
]
}
},
{
-45
View File
@@ -1,45 +0,0 @@
---
name: "\U0001F41B Bug"
about: Create a report to help us improve
title: ''
labels: "\U0001F41B bug"
assignees: ''
---
## Description
A clear and concise description of what the bug is.
## Steps to Reproduce
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
## Expected behavior
A clear and concise description of what you expected to happen.
## Screenshots
If applicable, add screenshots to help explain your problem.
## Device details
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
## Additional context
Add any other context about the problem here.
-21
View File
@@ -1,21 +0,0 @@
---
name: Chore
about:
A template to capture non feature / enhancement work we need to do like work
to support other functions or housekeeping etc.
title: ''
labels: chore
assignees: ''
---
## The Chore
What we need to achieve and who for
## Tasks
- [ ] What do we need to do first
- [ ] and then what?
- [ ] Etc.
## Additional details / background info
-33
View File
@@ -1,33 +0,0 @@
---
name: User Story
about:
A template to describe a features or enhancements we want to make from a users
perspective to ensure we understand what is needed and the value it would add
title: ''
labels: feature
assignees: ''
---
## Story
As a
I want
So that
## Acceptance Criteria
- [ ] I can
- [ ] I can
- [ ] I can
## Tasks
- [ ] Explore and sketch
- [ ] Team and stakeholder review
- [ ] Visual Design
- [ ] Team review
- [ ] Etc.
## Sketch
## Additional details / background info
@@ -1,51 +0,0 @@
outputs:
token:
description: 'api-token of wallet'
value: ${{ steps.generate-api-token.outputs.api-token }}
runs:
using: 'composite'
steps:
- name: Vegacapsule version
shell: bash
run: vegacapsule version
- name: Vega wallet version
shell: bash
run: vega wallet software version
- 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
- 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 ./frontend-monorepo/vegacapsule/passphrase --home ~/.vegacapsule/testnet/wallet
- name: Generate second public key
shell: bash
run: vega wallet key generate -w capsule_wallet -p ./frontend-monorepo/vegacapsule/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: Init api-token
shell: bash
run: vega wallet api-token init --home ~/.vegacapsule/testnet/wallet --passphrase-file ./frontend-monorepo/vegacapsule/passphrase
- name: Generate api-token
id: generate-api-token
shell: bash
run: echo api-token=$(vega wallet api-token generate --wallet-name capsule_wallet --tokens-passphrase-file ./frontend-monorepo/vegacapsule/passphrase --wallet-passphrase-file ./frontend-monorepo/vegacapsule/passphrase --home ~/.vegacapsule/testnet/wallet | grep -Eo '[a-zA-Z0-9]{64}') >> $GITHUB_OUTPUT
- name: Start service using capsule network
shell: bash
run: vega wallet service run -n DV --load-tokens --tokens-passphrase-file ./frontend-monorepo/vegacapsule/passphrase --no-version-check --automatic-consent --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'
@@ -0,0 +1,152 @@
name: Capsule tests -- manual trigger
# This workflow runs the frontend tests against chosen branch
on:
workflow_dispatch:
inputs:
project:
description: 'Project'
required: true
type: choice
options:
- explorer-e2e
- console-lite-e2e
- stats-e2e
- token-e2e
- trading-e2e
includeFlows:
description: 'Include long flows (if any)?'
required: true
type: boolean
default: true
jobs:
manual:
name: Run capsule tests -- manual trigger
runs-on: ubuntu-latest
env:
GO111MODULE: 'on'
GOPROXY: ${{ secrets.GO_PROXY }}
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
#######
## Checkout capsule
#######
# 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'
#######
## Build binaries
#######
- name: Build capsule
run: go install
working-directory: capsule
- name: Set GOBIN
run: echo GOBIN=$(go env GOPATH)/bin >> $GITHUB_ENV
- name: Checkout Vega
uses: actions/checkout@v2
with:
repository: vegaprotocol/vega
ref: develop
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
path: './vega'
- name: Install Vega binaries
run: go install -v ./cmd/vega
working-directory: vega
- name: Install Vega wallet binaries
run: go install ./cmd/vegawallet
working-directory: vega
- name: Install date-node binaries
run: go install ./cmd/data-node
working-directory: vega
######
## 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=./net_confs/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
######
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
- name: Install root dependencies
run: yarn install
- name: Run Cypress tests
run: yarn nx run ${{ github.event.inputs.project }}:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
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_INCLUDE_FLOWS: ${{ github.event.inputs.includeFlows }}
######
## Upload logs
######
- name: Logs
if: ${{ always() }}
run: vegacapsule network logs > vega-capsule-logs.txt
- uses: actions/upload-artifact@v2
with:
name: logs
path: ./vega-capsule-logs.txt
@@ -0,0 +1,137 @@
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 * * *'
jobs:
nightly:
name: Run capsule tests -- nightly
runs-on: ubuntu-latest
env:
GO111MODULE: 'on'
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
#######
## Checkout capsule
#######
# 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'
#######
## Build binaries
#######
- name: Build capsule
run: go install
working-directory: capsule
- name: Set GOBIN
run: echo GOBIN=$(go env GOPATH)/bin >> $GITHUB_ENV
- name: Checkout Vega
uses: actions/checkout@v2
with:
repository: vegaprotocol/vega
ref: develop
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
path: './vega'
- name: Install Vega binaries
run: go install -v ./cmd/vega
working-directory: vega
- name: Install Vega wallet binaries
run: go install ./cmd/vegawallet
working-directory: vega
- name: Install date-node binaries
run: go install ./cmd/data-node
working-directory: vega
######
## 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=./net_confs/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
######
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v2
with:
ref: master
fetch-depth: 0
- name: Install root dependencies
run: yarn install
- name: Run Cypress tests
run: yarn nx run-many --target=e2e --all --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
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_INCLUDE_FLOWS: true
######
## Upload logs
######
- name: Logs
if: ${{ always() }}
run: vegacapsule network logs > vega-capsule-logs.txt
- uses: actions/upload-artifact@v2
with:
name: logs
path: ./vega-capsule-logs.txt
+144
View File
@@ -0,0 +1,144 @@
name: Capsule tests
on:
push:
branches:
- master
- develop
pull_request:
jobs:
pr:
name: Run capsule tests - PR
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
env:
GO111MODULE: 'on'
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
#######
## Checkout capsule
#######
# 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'
#######
## Build binaries
#######
- name: Build capsule
run: go install
working-directory: capsule
- name: Set GOBIN
run: echo GOBIN=$(go env GOPATH)/bin >> $GITHUB_ENV
- name: Checkout Vega
uses: actions/checkout@v2
with:
repository: vegaprotocol/vega
ref: develop
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
path: './vega'
- name: Install Vega binaries
run: go install -v ./cmd/vega
working-directory: vega
- name: Install Vega wallet binaries
run: go install ./cmd/vegawallet
working-directory: vega
- name: Install date-node binaries
run: go install ./cmd/data-node
working-directory: vega
######
## 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=./net_confs/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
######
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v2
with:
main-branch-name: master
- name: Install root dependencies
run: yarn install
- name: Run Cypress tests
run: npx nx affected:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
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_INCLUDE_FLOWS: false
######
## Upload logs
######
- name: Logs
if: ${{ always() }}
run: vegacapsule network logs > vega-capsule-logs.txt
- uses: actions/upload-artifact@v2
if: ${{ always() }}
with:
name: logs
path: ./vega-capsule-logs.txt
-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 }}
@@ -1,33 +0,0 @@
name: Cypress tests -- manual trigger
# This workflow runs the frontend tests against chosen branch
on:
workflow_dispatch:
inputs:
project:
description: 'Project'
required: true
type: choice
options:
- explorer-e2e
- token-e2e
- trading-e2e
tags:
description: 'Test tags to run'
required: true
type: string
default: '@smoke @regression @slow'
skip-nx-cache:
description: 'Skip NX cache'
required: false
type: boolean
default: false
jobs:
manual:
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
with:
projects: '["${{inputs.project}}"]'
skip-cache: ${{inputs.skip-nx-cache}}
tags: ${{inputs.tags}}
-14
View File
@@ -1,14 +0,0 @@
name: Cypress tests -- night run
on:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:
jobs:
nightly:
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
with:
projects: '["explorer-e2e","token-e2e","trading-e2e"]'
tags: '@smoke @regression @slow'
-78
View File
@@ -1,78 +0,0 @@
name: Cypress tests - PR
on:
push:
branches:
- develop
- main
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
jobs:
pr:
runs-on: ubuntu-latest
steps:
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup node
uses: actions/setup-node@v3
- name: Remove package.json & yarn.lock to avoid installing everything
run: rm package.json yarn.lock
- name: Install nx
run: yarn add nx
# Check SHAs
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v2
with:
main-branch-name: ${{ github.base_ref || github.ref_name }}
set-environment-variables-for-job: true
# See affected apps
- name: See affected apps
run: |
affected=$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)
echo -n "Affected projects: $affected"
projects=""
if [[ $affected == *"token"* ]]; then projects+='"token-e2e" '; fi
if [[ $affected == *"trading"* ]]; then projects+='"trading-e2e" '; fi
if [[ $affected == *"explorer"* ]]; then projects+='"explorer-e2e" '; fi
if [[ -z "$projects" ]]; then projects+='"token-e2e" "trading-e2e" "explorer-e2e" '; fi
projects=${projects%?}
projects=[${projects// /,}]
echo PROJECTS=$projects >> $GITHUB_ENV
outputs:
projects: ${{ env.PROJECTS }}
run:
needs: pr
if: ${{ needs.pr.outputs.projects != '[]' }}
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
with:
projects: ${{ needs.pr.outputs.projects }}
tags: '@smoke @regression'
# Report single result at the end, to avoid mess with required checks in PR
result:
if: ${{ always() }}
needs: run
runs-on: ubuntu-latest
name: Cypress result
steps:
- run: |
result="${{ needs.run.result }}"
if [[ $result == "success" || $result == "skipped" ]]; then
exit 0
else
exit 1
fi
-90
View File
@@ -1,90 +0,0 @@
on:
workflow_call:
inputs:
projects:
required: true
type: string
skip-cache:
required: false
type: boolean
tags:
required: false
type: string
jobs:
e2e:
strategy:
fail-fast: false
matrix:
project: ${{ fromJSON(inputs.projects) }}
runs-on: self-hosted-runner
timeout-minutes: 30
steps:
# Checks if skip cache was requested
- name: Set skip-nx-cache flag
if: ${{ inputs.skip-cache == true }}
run: echo "SKIP_CACHE=--skip-nx-cache" >> $GITHUB_ENV
# 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', 'frontend-monorepo/package.json') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
# Make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
######
## Setup Vegacapsule and Vega wallet
######
- name: Run Vegacapsule network and Vega wallet
id: setup-vega
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
######
## Run some tests
######
- name: Run Cypress tests
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
working-directory: frontend-monorepo
env:
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_VEGA_WALLET_API_TOKEN: ${{ steps.setup-vega.outputs.token }}
CYPRESS_grepTags: ${{ inputs.tags }}
######
## Upload logs
######
# Artifact path is not valid: /ganache-1/capsule-logscolletor.stderr-2022-12-22T10:20:30Z.log. Contains the following character: Colon :
- name: Rename files to allow archive
if: ${{ always() }}
run: |
while read -r file; do
mv "${file}" "$(echo ${file} | sed 's|:|-|g')"
done< <(find /home/runner/.vegacapsule/testnet/logs -type f)
- uses: actions/upload-artifact@v3
if: ${{ always() }}
with:
name: logs-${{ matrix.project }}
path: /home/runner/.vegacapsule/testnet/logs
+1 -1
View File
@@ -3,7 +3,7 @@ name: Generate queries
on:
push:
branches:
- develop
- master
jobs:
master:
+32
View File
@@ -0,0 +1,32 @@
---
name: Deploy affected projects to IPFS
'on':
# Triggers the workflow on push to main branch
push:
branches: [master]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch: null
jobs:
master:
name: Publish NX Affected
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
- name: Use Node.js 16
id: Node
uses: actions/setup-node@v2
with:
node-version: 16.14.0
- name: Install root dependencies
run: yarn install
- name: Run deploy for affected sites
env:
FLEEK_API_KEY: ${{ secrets.FLEEK_API_KEY }}
run: ./tools/ipfs-deploy.js
-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
@@ -0,0 +1,60 @@
name: Publish NextJs containers
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-pre[0-9]+'
jobs:
master:
strategy:
matrix:
build-platform: ['linux/amd64']
app: ['trading']
name: Build the ${{ inputs.image_name }} image
runs-on: ubuntu-latest
steps:
- name: Set output
id: vars
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Check output
env:
RELEASE_VERSION: ${{ steps.vars.outputs.tag }}
run: |
echo $RELEASE_VERSION
echo ${{ steps.vars.outputs.tag }}
- uses: actions/checkout@v3
- name: Set up QEMU
id: quemu
uses: docker/setup-qemu-action@v2
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Collect images data
id: tags
run: |
echo '::set-output name=current::vegaprotocol/${{ matrix.app }}:${{ steps.vars.outputs.tag }}'
echo '::set-output name=latest::vegaprotocol/${{ matrix.app }}:latest'
- name: Echo tags
run: |
echo ${{ steps.tags.outputs.latest }}
echo ${{ steps.tags.outputs.current }}
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker build
uses: docker/build-push-action@v3
with:
context: '.'
file: './Dockerfile.next'
build-args: 'APP=${{ matrix.app }}'
platforms: ${{ matrix.build-platform }}
tags: ${{ steps.tags.outputs.latest }},${{ steps.tags.outputs.current }}
push: true
@@ -0,0 +1,60 @@
name: Publish CRA containers
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-pre[0-9]+'
jobs:
master:
strategy:
matrix:
build-platform: ['linux/amd64']
app: ['explorer', 'token']
name: Build the ${{ inputs.image_name }} image
runs-on: ubuntu-latest
steps:
- name: Set output
id: vars
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Check output
env:
RELEASE_VERSION: ${{ steps.vars.outputs.tag }}
run: |
echo $RELEASE_VERSION
echo ${{ steps.vars.outputs.tag }}
- uses: actions/checkout@v3
- name: Set up QEMU
id: quemu
uses: docker/setup-qemu-action@v2
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Collect images data
id: tags
run: |
echo '::set-output name=current::vegaprotocol/${{ matrix.app }}:${{ steps.vars.outputs.tag }}'
echo '::set-output name=latest::vegaprotocol/${{ matrix.app }}:latest'
- name: Echo tags
run: |
echo ${{ steps.tags.outputs.latest }}
echo ${{ steps.tags.outputs.current }}
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker build
uses: docker/build-push-action@v3
with:
context: '.'
file: './Dockerfile.cra'
build-args: 'APP=${{ matrix.app }}'
platforms: ${{ matrix.build-platform }}
tags: ${{ steps.tags.outputs.latest }},${{ steps.tags.outputs.current }}
push: true
@@ -1,126 +0,0 @@
name: Publish docker containers
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-*'
workflow_dispatch:
inputs:
publish:
description: 'Publish tag to Docker Hub & GitHub Registry'
required: false
type: boolean
default: false
tag:
description: 'Git Tag to build and publish'
required: false
type: string
default: ''
apps:
description: 'Applications to build and publish'
required: false
type: choice
options:
- '["explorer", "token", "trading"]'
- '["explorer"]'
- '["token"]'
- '["trading"]'
archs:
description: 'Architecture to build and publish'
required: false
type: choice
options:
- linux/amd64, linux/arm64
- linux/amd64
- linux/arm64
jobs:
master:
strategy:
fail-fast: false
matrix:
app: ${{ fromJson(inputs.apps || '["explorer", "token", "trading"]') }}
name: Build the ${{ matrix.app }} image
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
with:
ref: ${{ inputs.tag }}
- name: Set up QEMU
id: quemu
uses: docker/setup-qemu-action@v2
- name: Available platforms
run: echo ${{ steps.qemu.outputs.platforms }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
if: ${{ inputs.publish || startsWith(github.ref, 'refs/tags/') }}
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Determine Docker Image tag
id: tags
run: |
hash=$(git rev-parse HEAD|cut -b1-8)
versionTag=${{ inputs.tag || startsWith(github.ref, 'refs/tags/') && github.ref_name || '${hash}' }}
echo ::set-output name=version::${versionTag}
echo ::set-output name=npmVersion::$(cat dockerfiles/${{ matrix.app =='trading' && 'Dockerfile.next' || 'Dockerfile.cra' }} | grep FROM | head -n 1 | awk '{print $2}' | cut -d ':' -f 2 | cut -d '-' -f 1 )
- name: Print config
run: |
git rev-parse --verify HEAD
git status
echo "inputs.tag=${{ inputs.tag }}"
echo "inputs.publish=${{ inputs.publish }}"
echo "inputs.apps=${{ inputs.apps }}"
echo "inputs.archs=${{ inputs.archs }}"
echo "steps.tags.outputs.version=${{ steps.tags.outputs.version }}"
- uses: actions/setup-node@v3
with:
node-version: ${{ steps.tags.outputs.npmVersion }}
- name: Build frontend dists
run: |
yarn --verbose --pure-lockfile
yarn nx ${{ matrix.app =='trading' && 'export' || 'build' }} ${{ matrix.app }} --pure-lockfile
- name: Build and export to local Docker
uses: docker/build-push-action@v3
with:
context: .
push: false
file: dockerfiles/${{ matrix.app =='trading' && 'Dockerfile.next' || 'Dockerfile.cra' }}.dist
build-args: APP=${{ matrix.app }}
load: true
tags: vegaprotocol/${{ matrix.app }}:local
- name: Sanity check docker image
run: |
docker run --rm vegaprotocol/${{ matrix.app }}:local cat .env
docker run --rm vegaprotocol/${{ matrix.app }}:local ls -lah
- name: Build and push to DockerHub
id: docker_build
uses: docker/build-push-action@v3
with:
context: .
push: ${{ inputs.publish || startsWith(github.ref, 'refs/tags/') }}
file: dockerfiles/${{ matrix.app =='trading' && 'Dockerfile.next' || 'Dockerfile.cra' }}.dist
build-args: APP=${{ matrix.app }}
platforms: ${{ inputs.archs || 'linux/amd64, linux/arm64' }}
tags: |
vegaprotocol/${{ matrix.app }}:latest
vegaprotocol/${{ matrix.app }}:${{ steps.tags.outputs.version }}
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
+38 -17
View File
@@ -3,37 +3,60 @@ name: Unit tests & build
on:
push:
branches:
- master
- develop
- main
pull_request:
jobs:
pr:
name: Test and lint - PR
master:
name: Test and lint - main
runs-on: ubuntu-latest
permissions:
contents: 'read'
actions: 'read'
if: ${{ github.event_name != 'pull_request' }}
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v2
with:
main-branch-name: ${{ github.base_ref }}
main-branch-name: master
- name: Use Node.js 16
id: Node
uses: actions/setup-node@v3
uses: actions/setup-node@v2
with:
node-version: 16.14.0
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: '**/node_modules'
key: node_modules-${{ hashFiles('**/yarn.lock') }}
- name: Install root dependencies
run: yarn install --frozen-lockfile
run: yarn install
- name: Check formatting
run: yarn nx format:check
- name: Lint affected
run: yarn nx affected:lint --max-warnings=0
- name: Test affected
run: yarn nx affected:test
- name: Build affected
run: yarn nx affected:build
pr:
name: Test and lint - PR
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v2
with:
main-branch-name: master
- name: Use Node.js 16
id: Node
uses: actions/setup-node@v2
with:
node-version: 16.14.0
- name: Install root dependencies
run: yarn install
- name: Check formatting
run: yarn nx format:check
- name: Lint affected
@@ -42,5 +65,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
-3
View File
@@ -43,6 +43,3 @@ Thumbs.db
.local.env
.env.local
cypress.env.json
# Next.js
.next
+4
View File
@@ -6,3 +6,7 @@ yarn commitlint --edit "${1}"
# Lint all staged files
yarn lint-staged
# Build & test affected apps
yarn nx affected:build --uncommitted
yarn nx affected:test --uncommitted
-1
View File
@@ -3,7 +3,6 @@
/dist
/coverage
__generated__
__generated___
apps/static/src/assets/devnet-tranches.json
apps/static/src/assets/mainnet-tranches.json
+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
-1
View File
@@ -1,2 +1 @@
* @vegaprotocol/frontend
*.graphql @vegaprotocol/core
@@ -8,8 +8,8 @@ COPY package.json ./
COPY yarn.lock ./
COPY . ./
RUN apk add python3 make gcc g++
RUN yarn --network-timeout 100000 --verbose --pure-lockfile
RUN yarn nx build $APP --network-timeout 100000 --verbose --pure-lockfile
RUN yarn
RUN yarn nx build $APP
# Production environment
FROM nginx:stable-alpine
@@ -8,8 +8,8 @@ COPY package.json ./
COPY yarn.lock ./
COPY . ./
RUN apk add python3 make gcc g++
RUN yarn --network-timeout 100000 --verbose --pure-lockfile
RUN yarn nx export $APP --network-timeout 100000 --verbose --pure-lockfile
RUN yarn
RUN yarn nx export $APP
# Production environment
FROM nginx:stable-alpine
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'
}
}
}
}
+13 -44
View File
@@ -22,14 +22,14 @@ The utility dApp for interacting with the Vega token and using its' utility. Thi
The block explorer for the Vega network, showing details of raw chain states and the state of markets on the Vega network.
### [Stats](./apps/stats)
An application for the status of the Vega network. Showing block height and other network activity.
### [Static](./apps/static)
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)
@@ -69,10 +69,10 @@ Run `nx serve my-app` for a dev server. Navigate to the port specified in `app/<
### Using Apollo GraphQL and Generate Types
In order to generate the schemas for your GraphQL queries, you can run `GRAPHQL_SCHEMA_PATH=[YOUR SCHEMA FILE / API URL HERE] nx run types:generate`.
In order to generate the schemas for your GraphQL queries, you can run `NX_VEGA_URL=[YOUR URL HERE] nx run types:generate`.
```bash
export GRAPHQL_SCHEMA_PATH=https://api.n11.testnet.vega.xyz/graphql
export NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
yarn nx run types:generate
```
@@ -82,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 make sure you have generated at least two public keys and update the following environment variables in `cypress.config.js` to match your wallet.
To run tests locally using your own wallets you can add the following environment variables to `cypress.json`
1. Set `VEGA_PUBLIC_KEY` and `TRUNCATED_VEGA_PUBLIC_KEY` to your first public key.
2. Set `VEGA_PUBLIC_KEY2` and `TRUNCATED_VEGA_PUBLIC_KEY2` to your second public key.
3. Set `TRADING_TEST_VEGA_WALLET_PASSPHRASE` as your wallet passphrase
4. Add `ETH_WALLET_MNEMONIC` as your Ethereum wallet mnemonic
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
### Formatting
@@ -107,12 +106,12 @@ Visit the [Nx Documentation](https://nx.dev/getting-started/intro) to learn more
## Docker
The [Dockerfile](./dockerfiles) for running the frontends is pretty basic, merely building the application with the APP arg that is passed in and serving the application from [nginx](./nginx/nginx.conf). The only complexity that exists is that there is a script which allows the passing of run time environment variables to the containers. See configuration below for how to do this.
The [Dockerfile](./Dockerfile) for running the frontends is pretty basic, merely building the application with the APP arg that is passed in and serving the application from [nginx](./nginx/nginx.conf). The only complexity that exists is that there is a script which allows the passing of run time environment variables to the containers. See configuration below for how to do this.
You can build any of the containers locally with the following command:
```bash
docker build --dockerfile dockerfiles/Dockerfile.cra . --build-arg APP=[YOUR APP] --tag=[TAG]
docker build . --build-arg APP=[YOUR APP] --tag=[TAG]
```
In order to run a container:
@@ -121,8 +120,6 @@ In order to run a container:
docker run -p 3000:80 [TAG]
```
Images ending with `.dist` are to pack locally created transpiled HTML files into nginx container for non-compatible with yarn architectures like M1 Mac
## Config
As environment variables are build time and not run time in frontend applications. We have built a system which allows for passing run time environment variables, this generates a JSON file that will override the default environment variables that the container was built with (which is always testnet, using the default .env files).
@@ -141,34 +138,6 @@ Coming soon! You will be able to run the containers within Vega Capsule.
You can run against a local instance of Vega Capsule today by using the .env.capsule present in the apps.
If you wish to run E2E tests for Token and Block Explorer (other areas to be added soon)
- Vegacapsule must be used in order for these tests to succeed, the vegacapsule repo README.md file contains the steps required to set this up, it must be installed globally.
- However we start the capsule network a little differently to how it is laid out in those instructions:
In order to run the bootstrap command to generate and start a new network, we must do so using the following:
```bash
vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl
```
In order to setup and run vegawallet for e2e capsule tests, in a separate terminal window:
1. cd into `./vegacapsule`
2. run:
```bash
bash setup-vegawallet.sh
```
3. copy generated `api-token` and paste the token into `CYPRESS_VEGA_WALLET_API_TOKEN` environment variable in either `apps/token-e2e/.env` or `apps/explorer-e2e/.env` depending on which project needs testing.
Note: The script is only needed if capsule was built for first time or fresh. To run existing wallet service for capsule:
```bash
vega wallet service run -n DV --load-tokens --tokens-passphrase-file passphrase --no-version-check --automatic-consent --home ~/.vegacapsule/testnet/wallet
```
# 📑 License
[MIT](./LICENSE)
+27
View File
@@ -0,0 +1,27 @@
# 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_REST=https://api.n11.testnet.vega.xyz
NX_VEGA_WALLET_URL=http://localhost:1789/api/v1
+10
View File
@@ -0,0 +1,10 @@
{
"extends": ["plugin:cypress/recommended", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
}
]
}
+39
View File
@@ -0,0 +1,39 @@
const { defineConfig } = require('cypress');
module.exports = defineConfig({
projectId: 'et4snf',
e2e: {
baseUrl: 'http://localhost:4200',
fileServerFolder: '.',
fixturesFolder: false,
specPattern: './src/integration/*.ts',
excludeSpecPattern: '**/*.js',
modifyObstructiveCode: false,
supportFile: './src/support/index.ts',
video: true,
videoUploadOnPasses: false,
videosFolder: '../../dist/cypress/apps/console-lite-e2e/videos',
screenshotsFolder: '../../dist/cypress/apps/console-lite-e2e/screenshots',
chromeWebSecurity: false,
viewportWidth: 1440,
viewportHeight: 900,
},
env: {
TRADING_TEST_VEGA_WALLET_NAME: 'UI_Trading_Test',
ETHEREUM_PROVIDER_URL:
'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
VEGA_PUBLIC_KEY:
'47836c253520d2661bf5bed6339c0de08fd02cf5d4db0efee3b4373f20c7d278',
VEGA_PUBLIC_KEY2:
'1a18cdcaaa4f44a57b35a4e9b77e0701c17a476f2b407620f8c17371740cf2e4',
TRUNCATED_VEGA_PUBLIC_KEY: '47836c…c7d278',
TRUNCATED_VEGA_PUBLIC_KEY2: '1a18cd…0cf2e4',
ETHEREUM_WALLET_ADDRESS: '0x265Cc6d39a1B53d0d92068443009eE7410807158',
ETHERSCAN_URL: 'https://ropsten.etherscan.io',
tsConfig: 'tsconfig.json',
TAGS: 'not @todo and not @ignore and not @manual',
TRADING_TEST_VEGA_WALLET_PASSPHRASE: '123',
ETH_WALLET_MNEMONIC:
'ugly gallery notice network true range brave clarify flat logic someone chunk',
},
});
+28
View File
@@ -0,0 +1,28 @@
{
"root": "apps/console-lite-e2e",
"sourceRoot": "apps/console-lite-e2e/src",
"projectType": "application",
"targets": {
"e2e": {
"executor": "@nrwl/cypress:cypress",
"options": {
"cypressConfig": "apps/console-lite-e2e/cypress.config.js",
"devServerTarget": "console-lite:serve"
},
"configurations": {
"production": {
"devServerTarget": "console-lite:serve:production"
}
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/console-lite-e2e/**/*.{js,ts}"]
}
}
},
"tags": [],
"implicitDependencies": ["console-lite"]
}
@@ -0,0 +1,7 @@
describe('simple trading app', () => {
beforeEach(() => cy.visit('/'));
it('render', () => {
cy.get('#root').should('exist');
});
});
@@ -0,0 +1,30 @@
describe('console lite header', () => {
beforeEach(() => {
window.localStorage.setItem('theme', 'dark');
cy.visit('/');
});
it('logo should linked home', () => {
cy.get('span').contains('Markets').click();
cy.location('pathname').should('eq', '/markets');
cy.getByTestId('header').find('a').click();
cy.location('pathname').should('eq', '/');
});
it('theme switcher should switch theme', () => {
cy.get('#root').children().eq(0).as('Container');
cy.get('@Container').should('have.css', 'background-color', 'rgb(8, 8, 8)');
cy.getByTestId('theme-switcher').click();
cy.get('@Container').should(
'have.css',
'background-color',
'rgb(255, 255, 255)'
);
});
it('wallet connector should open a dialog', () => {
cy.get('[role="dialog"]').should('not.exist');
cy.getByTestId('connect-vega-wallet').click();
cy.get('[role="dialog"]').should('be.visible');
});
});
@@ -0,0 +1,131 @@
import { aliasQuery } from '@vegaprotocol/cypress';
import {
generateLongListMarkets,
generateSimpleMarkets,
} from '../support/mocks/generate-markets';
describe('market list', () => {
describe('simple url', () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
});
cy.visit('/markets');
});
it('selects menus', () => {
cy.get('[aria-label="Sidebar Navigation Menu"] [aria-current]').should(
'have.text',
'Markets'
);
cy.getByTestId('state-trigger').should('have.text', 'Active');
cy.get('[aria-label="Future"]').click();
cy.get('[data-testid="market-assets-menu"] a.active').should(
'have.text',
'All'
);
});
it('navigation should make possibly shortest url', () => {
cy.location('pathname').should('equal', '/markets');
cy.getByTestId('state-trigger').click();
cy.get('[role=menuitemcheckbox]').contains('All').click();
cy.location('pathname').should('equal', '/markets/all');
cy.get('[aria-label="Future"]').click();
cy.location('pathname').should('eq', '/markets/all/Future');
let asset = '';
cy.getByTestId('market-assets-menu')
.children()
.then((children) => {
if (children.length > 1) {
asset = children[1].innerText;
if (asset) {
cy.wrap(children[1]).click();
cy.location('pathname').should(
'match',
new RegExp(`/markets/all/Future/${asset}`, 'i')
);
cy.get('a').contains('All Markets').click();
cy.location('pathname').should('eq', '/markets/all');
}
}
});
cy.getByTestId('state-trigger').click();
cy.get('[role=menuitemcheckbox]').contains('Active').click();
cy.location('pathname').should('equal', '/markets');
});
});
describe('url params should select filters', () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
});
});
it('suspended status', () => {
cy.visit('/markets/Suspended');
cy.getByTestId('state-trigger').should('have.text', 'Suspended');
});
it('last asset (if exists)', () => {
cy.visit('/markets');
cy.wait('@SimpleMarkets').then((filters) => {
if (filters?.response?.body?.data?.markets?.length) {
const asset =
filters.response.body.data.markets[0].tradableInstrument.instrument
.product.settlementAsset.symbol;
cy.visit(`/markets/Suspended/Future/${asset}`);
cy.getByTestId('market-assets-menu')
.find('a.active')
.should('have.text', asset);
}
});
});
it('Future product', () => {
cy.visit('/markets/Suspended/Future');
cy.getByTestId('market-products-menu')
.find('a.active')
.should('have.text', 'Future');
});
});
describe('long list of results should be handled properly', () => {
it('handles 5000 markets', () => {
cy.viewport(1440, 900);
cy.mockGQL((req) => {
aliasQuery(req, 'SimpleMarkets', generateLongListMarkets(5000));
});
performance.mark('start-5k');
cy.visit('/markets');
cy.get('.ag-center-cols-container', { timeout: 50000 }).then(() => {
performance.mark('end-5k');
performance.measure('load-5k', 'start-5k', 'end-5k');
const measure = performance.getEntriesByName('load-5k')[0];
expect(measure.duration).lte(20000);
cy.log(`Ag-grid 5k load took ${measure.duration} milliseconds.`);
cy.get('.ag-root').should('have.attr', 'aria-rowcount', '5001');
cy.get('.ag-center-cols-container')
.find('[role="row"]')
.its('length')
.then((length) => expect(length).to.be.closeTo(21, 2));
cy.get('.ag-cell-label-container').eq(4).click();
cy.get('body').then(($body) => {
for (let i = 0; i < 20; i++) {
cy.wrap($body).realPress('Tab', { pressDelay: 300 });
}
});
cy.focused().parent('.ag-row').should('have.attr', 'row-index', '19');
cy.get('.ag-center-cols-container')
.find('[role="row"]')
.its('length')
.then((length) => expect(length).to.be.closeTo(31, 2));
});
});
});
});
@@ -0,0 +1,138 @@
import { connectVegaWallet } from '../support/connect-wallet';
import { aliasQuery } from '@vegaprotocol/cypress';
import { 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';
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 { generateMarketNames } from '../support/mocks/generate-market-names';
describe('market selector', () => {
let markets;
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
aliasQuery(req, 'DealTicketQuery', generateDealTicket());
aliasQuery(req, 'MarketTags', generateMarketTags());
aliasQuery(req, 'MarketPositions', generateMarketPositions());
aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
aliasQuery(req, 'PartyBalanceQuery', generatePartyBalance());
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
aliasQuery(req, 'MarketNames', generateMarketNames());
});
cy.visit('/markets');
cy.wait('@SimpleMarkets').then((response) => {
if (response.response.body.data?.markets?.length) {
markets = response.response.body.data.markets;
}
});
});
it('should be properly rendered', () => {
if (markets?.length) {
cy.visit(`/trading/${markets[0].id}`);
connectVegaWallet();
cy.get('input[placeholder="Search"]').should(
'have.value',
markets[0].name
);
cy.getByTestId('arrow-button').click();
cy.getByTestId('market-pane').should('be.visible');
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.first()
.should('contain.text', markets[0].name);
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.first()
.click();
cy.getByTestId('market-pane').should('not.be.visible');
}
});
it('typing should change list', () => {
if (markets?.length) {
cy.visit(`/trading/${markets[0].id}`);
connectVegaWallet();
cy.get('input[placeholder="Search"]').type('{backspace}');
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.should('have.length.at.least', 1);
cy.get('input[placeholder="Search"]').clear();
cy.get('input[placeholder="Search"]').type('aa');
const filtered = markets.filter(
(market) =>
market.data.market.state === 'STATE_ACTIVE' &&
market.name.match(/aa/i)
);
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.should('have.length', filtered.length);
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.last()
.click();
cy.location('pathname').should(
'eq',
`/trading/${filtered[filtered.length - 1].id}`
);
cy.get('input[placeholder="Search"]').should(
'have.value',
filtered[filtered.length - 1].name
);
}
});
it('keyboard navigation should work well', () => {
if (markets?.length) {
cy.visit(`/trading/${markets[0].id}`);
connectVegaWallet();
cy.get('input[placeholder="Search"]').type('{backspace}');
cy.get('input[placeholder="Search"]').clear();
cy.get('body').realPress('ArrowDown');
cy.focused().eq(0).should('contain.text', 'AAVEDAI Monthly');
cy.get('body').realPress('ArrowDown');
cy.focused().eq(0).should('contain.text', 'ETHBTC').realPress('Enter');
cy.location('pathname').should('eq', '/trading/ethbtc-quaterly');
cy.get('input[placeholder="Search"]').type('{backspace}');
cy.get('input[placeholder="Search"]').clear();
cy.getByTestId('market-pane').should('be.visible');
cy.get('body').realPress('ArrowDown');
cy.get('body').realPress('Tab');
cy.getByTestId('market-pane').should('not.be.visible');
}
});
it('mobile view', () => {
if (markets?.length) {
cy.viewport('iphone-xr');
cy.visit(`/trading/${markets[0].id}`);
connectVegaWallet();
cy.get('[role="dialog"]').should('not.exist');
cy.getByTestId('arrow-button').click();
cy.get('[role="dialog"]').should('be.visible');
cy.get('input[placeholder="Search"]').clear();
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.should('have.length', 3);
cy.get('div[role="dialog"]').should('have.class', 'w-full');
cy.getByTestId('dialog-close').click();
cy.get('input[placeholder="Search"]').should(
'have.value',
markets[0].name
);
}
});
});
@@ -0,0 +1,271 @@
import { aliasQuery } from '@vegaprotocol/cypress';
import { 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';
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 { connectVegaWallet } from '../support/connect-wallet';
describe('Market trade', () => {
let markets;
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
aliasQuery(req, 'DealTicketQuery', generateDealTicket());
aliasQuery(req, 'MarketTags', generateMarketTags());
aliasQuery(req, 'MarketPositions', generateMarketPositions());
aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
aliasQuery(req, 'PartyBalanceQuery', generatePartyBalance());
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
});
cy.visit('/markets');
cy.wait('@SimpleMarkets').then((response) => {
if (response.response.body.data?.markets?.length) {
markets = response.response.body.data.markets;
}
});
});
it('should not display steps if wallet is disconnected', () => {
cy.visit(`/trading/${markets[0].id}`);
cy.getByTestId('trading-connect-wallet')
.find('h3')
.should('have.text', 'Please connect your Vega wallet to make a trade');
cy.getByTestId('trading-connect-wallet')
.find('button')
.should('have.text', 'Connect Vega wallet');
cy.getByTestId('trading-connect-wallet')
.find('a')
.should('have.text', 'https://vega.xyz/wallet');
});
it('side selector should work well', () => {
if (markets?.length) {
cy.visit(`/trading/${markets[0].id}`);
connectVegaWallet();
cy.get('#step-1-control [aria-label^="Selected value"]').should(
'have.text',
'Long'
);
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-1-control [aria-label^="Selected value"]').should(
'have.text',
'Short'
);
}
});
it('side selector mobile view should work well', () => {
if (markets?.length) {
cy.viewport('iphone-xr');
cy.visit(`/trading/${markets[0].id}`);
connectVegaWallet();
cy.getByTestId('next-button').scrollIntoView().click();
cy.get('button[aria-label="Open long position"]').should(
'have.class',
'selected'
);
cy.get('button[aria-label="Open short position"]').should(
'not.have.class',
'selected'
);
cy.get('button[aria-label="Open short position"]').click();
cy.get('button[aria-label="Open long position"]').should(
'not.have.class',
'selected'
);
cy.get('button[aria-label="Open short position"]').should(
'have.class',
'selected'
);
cy.getByTestId('next-button').scrollIntoView().click();
cy.get('#step-1-control').should(
'contain.html',
'aria-label="Selected value Short"'
);
}
});
it('size slider should work well', () => {
if (markets?.length) {
cy.visit(`/trading/${markets[1].id}`);
connectVegaWallet();
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '1');
cy.get('#step-2-panel').find('[role="slider"]').type('{rightarrow}');
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '2');
}
});
it('percentage selection should work well', () => {
if (markets?.length) {
cy.visit(`/trading/${markets[1].id}`);
connectVegaWallet();
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '1');
cy.getByTestId('max-label').should('have.text', '21');
cy.getByTestId('percentage-selector')
.find('button')
.contains('Max')
.click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '21');
}
});
it('size input should work well', () => {
if (markets?.length) {
cy.visit(`/trading/${markets[1].id}`);
connectVegaWallet();
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '1');
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('input')
.type('{backspace}2');
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '2');
}
});
it('notional position size should be present', () => {
if (markets?.length) {
cy.visit(`/trading/${markets[1].id}`);
connectVegaWallet();
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '1');
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('input')
.type('{backspace}2');
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
cy.get('#step-2-panel')
.find('dt')
.eq(2)
.should('have.text', 'Est. Position Size (tDAI)');
cy.get('#step-2-panel').find('dd').eq(2).should('have.text', '197.86012');
}
});
it('total fees should be displayed', () => {
if (markets?.length) {
cy.visit(`/trading/${markets[1].id}`);
connectVegaWallet();
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-2-panel')
.find('dt')
.eq(3)
.should('have.text', 'Est. Fees (tDAI)');
cy.get('#step-2-panel')
.find('dd')
.eq(3)
.should('have.text', '3.00000 (3.03%)');
}
});
it('order review should display proper calculations', () => {
if (markets?.length) {
cy.visit(`/trading/${markets[0].id}`);
connectVegaWallet();
cy.get('#step-3-control').click();
cy.getByTestId('review-trade')
.get('#contracts_tooltip_trigger')
.trigger('click')
.realTouch();
cy.get('[data-radix-popper-content-wrapper]').contains(
'The number of contracts determines'
);
cy.get('#step-3-panel').find('dd').eq(1).should('have.text', '1');
cy.get('#step-3-panel').find('dd').eq(2).should('have.text', '98.93006');
cy.get('#step-3-panel')
.find('dd')
.eq(3)
.should('have.text', '3.00000 (3.03%)');
cy.get('#step-3-panel').find('dd').eq(4).should('have.text', ' - ');
cy.getByTestId('place-order').click();
cy.getByTestId('dialog-title').should(
'have.text',
'Confirm transaction in wallet'
);
}
});
it('info tooltip on mobile view should work well', () => {
if (markets?.length) {
cy.viewport('iphone-xr');
cy.visit(`/trading/${markets[0].id}`);
connectVegaWallet();
cy.get('#step-3-control').click();
cy.getByTestId('review-trade')
.get('#contracts_tooltip_trigger')
.realTouch();
cy.get('[data-radix-popper-content-wrapper]').contains(
'The number of contracts determines'
);
cy.getByTestId('review-trade').get('div.cursor-help').eq(1).realTouch();
cy.get('[data-radix-popper-content-wrapper]').contains(
'The notional size represents the position size'
);
}
});
});
@@ -0,0 +1,34 @@
import {
connectVegaWallet,
disconnectVegaWallet,
} from '../support/connect-wallet';
describe('Portfolio page', () => {
afterEach(() => {
disconnectVegaWallet();
});
it('button for wallet connect should work', () => {
cy.visit('/');
cy.get('[href="/portfolio"]').eq(0).click();
cy.getByTestId('trading-connect-wallet').should('be.visible');
connectVegaWallet();
cy.getByTestId('trading-connect-wallet').should('not.exist');
});
it('certain tabs should exist', () => {
cy.visit('/portfolio');
connectVegaWallet();
cy.getByTestId('Assets').should('exist');
cy.getByTestId('tab-assets').should('exist');
cy.getByTestId('Positions').click();
cy.getByTestId('tab-positions').should('exist');
cy.getByTestId('Orders').click();
cy.getByTestId('tab-orders').should('exist');
cy.getByTestId('Fills').click();
cy.getByTestId('tab-fills').should('exist');
});
});
@@ -0,0 +1,9 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
@@ -0,0 +1,16 @@
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('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();
};
@@ -14,6 +14,6 @@
// ***********************************************************
import '@vegaprotocol/cypress';
import './common.functions.js';
import registerCypressGrep from '@cypress/grep';
registerCypressGrep();
import 'cypress-real-events/support';
// Import commands.js using ES2015 syntax:
import './commands';
@@ -0,0 +1,112 @@
const protoCandles = [
{ open: '9556163', close: '9587028', __typename: 'Candle' },
{
open: '9587028',
close: '9769899',
__typename: 'Candle',
},
{ open: '9769899', close: '9586292', __typename: 'Candle' },
{
open: '9586292',
close: '9261774',
__typename: 'Candle',
},
{ open: '9261773', close: '9236369', __typename: 'Candle' },
{
open: '9236369',
close: '9226070',
__typename: 'Candle',
},
{ open: '9226077', close: '9233252', __typename: 'Candle' },
{
open: '9249854',
close: '9333038',
__typename: 'Candle',
},
{ open: '9333038', close: '9410371', __typename: 'Candle' },
{
open: '9410371',
close: '9626249',
__typename: 'Candle',
},
{ open: '9626247', close: '9493253', __typename: 'Candle' },
{
open: '9493253',
close: '9309054',
__typename: 'Candle',
},
{ open: '9309054', close: '9378428', __typename: 'Candle' },
{
open: '9378428',
close: '9352996',
__typename: 'Candle',
},
{ open: '9352996', close: '9451142', __typename: 'Candle' },
{
open: '9451142',
close: '9691070',
__typename: 'Candle',
},
{ open: '9691071', close: '9622031', __typename: 'Candle' },
{
open: '9622034',
close: '9519285',
__typename: 'Candle',
},
{ open: '9528904', close: '9671275', __typename: 'Candle' },
{
open: '9671275',
close: '9988454',
__typename: 'Candle',
},
{ open: '9982457', close: '10085537', __typename: 'Candle' },
{
open: '10085537',
close: '9967390',
__typename: 'Candle',
},
{ open: '9967390', close: '9974844', __typename: 'Candle' },
{
open: '9974844',
close: '9940706',
__typename: 'Candle',
},
];
export const protoMarket = {
id: 'first-btcusd-id',
name: 'AAVEDAI Monthly (30 Jun 2022)',
data: {
market: {
id: 'first-btcusd-id',
state: 'STATE_ACTIVE',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'AAVEDAI.MF21',
metadata: {
tags: [
'formerly:2839D9B2329C9E70',
'base:AAVE',
'quote:DAI',
'class:fx/crypto',
'monthly',
'sector:defi',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'DAI',
settlementAsset: { symbol: 'tDAI', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: protoCandles,
__typename: 'Market',
};
@@ -0,0 +1,33 @@
export const generateDealTicket = () => {
return {
market: {
id: 'first-btcusd-id',
name: 'AAVEDAI Monthly (30 Jun 2022)',
decimalPlaces: 5,
positionDecimalPlaces: 0,
state: 'STATE_ACTIVE',
tradingMode: 'Continuous',
tradableInstrument: {
instrument: {
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',
},
};
};
@@ -0,0 +1,17 @@
export const generateEstimateOrder = () => {
return {
estimateOrder: {
fee: {
__typename: 'TradeFee',
makerFee: '100000',
liquidityFee: '100000',
infrastructureFee: '100000',
},
marginLevels: {
initialLevel: '2844054.80937741220203',
__typename: 'MarginLevels',
},
__typename: 'OrderEstimate',
},
};
};
@@ -0,0 +1,9 @@
export const generateMarketMarkPrice = () => {
return {
market: {
decimalPlaces: 5,
data: { markPrice: '692748', __typename: 'MarketData' },
__typename: 'Market',
},
};
};
@@ -0,0 +1,136 @@
import { protoMarket } from './commons';
export const generateMarketNames = () => {
return {
markets: [
{ ...protoMarket },
{
id: '1d7ddf67dac4924db03f5bf58571a7bcb1908d70c66580467717aabc5345b68a',
name: 'Apple Monthly (30 Jun 2022)',
state: 'STATE_SUSPENDED',
tradableInstrument: {
instrument: {
code: 'AAPL.MF21',
metadata: {
tags: [
'formerly:4899E01009F1A721',
'quote:USD',
'ticker:AAPL',
'class:equities/single-stock-futures',
'sector:tech',
'listing_venue:NASDAQ',
'country:US',
],
__typename: 'InstrumentMetadata',
},
product: { quoteName: 'USD', __typename: 'Future' },
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market',
},
{
id: '87ae87cd3244fc1fab4b0e2dad2437879864192bb969f3109b69293421644c8b',
name: 'Tesla Quarterly (30 Jun 2022)',
state: 'STATE_SUSPENDED',
tradableInstrument: {
instrument: {
code: 'TSLA.QM21',
metadata: {
tags: [
'formerly:5A86B190C384997F',
'quote:EURO',
'ticker:TSLA',
'class:equities/single-stock-futures',
'sector:tech',
'listing_venue:NASDAQ',
'country:US',
],
__typename: 'InstrumentMetadata',
},
product: { quoteName: 'EURO', __typename: 'Future' },
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market',
},
{
id: '69205712a854f1bbfb69fa3d11b60e01a1e249bafb5ece88115e7451e8ef07b3',
name: 'BTCUSD Monthly (30 Jun 2022)',
state: 'STATE_SUSPENDED',
tradableInstrument: {
instrument: {
code: 'BTCUSD.MF21',
metadata: {
tags: [
'formerly:076BB86A5AA41E3E',
'base:BTC',
'quote:USD',
'class:fx/crypto',
'monthly',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: { quoteName: 'USD', __typename: 'Future' },
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market',
},
{
id: 'ethbtc-quaterly',
name: 'ETHBTC Quarterly (30 Jun 2022)',
state: 'STATE_ACTIVE',
tradableInstrument: {
instrument: {
code: 'ETHBTC.QM21',
metadata: {
tags: [
'formerly:1F0BB6EB5703B099',
'base:ETH',
'quote:BTC',
'class:fx/crypto',
'quarterly',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: { quoteName: 'BTC', __typename: 'Future' },
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market',
},
{
id: '3c62b2714c4332d1a689a5352bff090e6aabccfd6bd87ce018936b38372530c9',
name: 'UNIDAI Monthly (30 Jun 2022)',
state: 'STATE_ACTIVE',
tradableInstrument: {
instrument: {
code: 'UNIDAI.MF21',
metadata: {
tags: [
'formerly:3C58ED2A4A6C5D7E',
'base:UNI',
'quote:DAI',
'class:fx/crypto',
'monthly',
'sector:defi',
],
__typename: 'InstrumentMetadata',
},
product: { quoteName: 'DAI', __typename: 'Future' },
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market',
},
],
};
};
@@ -0,0 +1,59 @@
export const generateMarketPositions = () => {
return {
party: {
id: '2e1ef32e5804e14232406aebaad719087d326afa5c648b7824d0823d8a46c8d1',
accounts: [
{
type: 'General',
asset: {
decimals: 5,
},
balance: '400000000000000000000',
market: {
id: '2751c508f9759761f912890f37fb3f97a00300bf7685c02a56a86e05facfe221',
__typename: 'Market',
},
},
{
type: 'Margin',
asset: {
decimals: 5,
},
balance: '265329',
market: {
id: 'first-btcusd-id',
__typename: 'Market',
},
},
],
positionsConnection: {
edges: [
{
node: {
openVolume: '3',
market: {
id: '2751c508f9759761f912890f37fb3f97a00300bf7685c02a56a86e05facfe221',
__typename: 'Market',
},
__typename: 'Position',
},
__typename: 'PositionEdge',
},
{
node: {
openVolume: '12',
market: {
id: 'first-btcusd-id',
__typename: 'Market',
},
__typename: 'Position',
},
__typename: 'PositionEdge',
},
],
__typename: 'PositionConnection',
},
__typename: 'Party',
},
};
};
@@ -0,0 +1,25 @@
export const generateMarketTags = () => {
return {
market: {
tradableInstrument: {
instrument: {
metadata: {
tags: [
'formerly:2839D9B2329C9E70',
'base:AAVE',
'quote:DAI',
'class:fx/crypto',
'monthly',
'sector:defi',
'settlement:2022-08-01',
],
__typename: 'InstrumentMetadata',
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market',
},
};
};
@@ -0,0 +1,993 @@
import { protoMarket } from './commons';
export const generateSimpleMarkets = () => {
return {
markets: [
{ ...protoMarket },
{
id: '57fbaa322e97cfc8bb5f1de048c37e033c41b1ac1906d3aed9960912a067ef5a',
name: 'CELUSD (June 2022)',
state: 'Active',
data: {
market: {
id: '57fbaa322e97cfc8bb5f1de048c37e033c41b1ac1906d3aed9960912a067ef5a',
state: 'STATE_PENDING',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'CELUSD',
metadata: {
tags: [
'base:CEL',
'quote:USD',
'class:fx/crypto',
'ad-hoc',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'USD',
settlementAsset: { symbol: 'XYZalpha', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: null,
__typename: 'Market',
},
{
id: 'ccf2f04865e5951ac3405da6e16b7cbdb535a0ad32df4df2dbed4262cf473255',
name: 'XMRUSD market',
state: 'Suspended',
data: {
market: {
id: 'ccf2f04865e5951ac3405da6e16b7cbdb535a0ad32df4df2dbed4262cf473255',
state: 'STATE_PROPOSED',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'XMRUSD',
metadata: {
tags: [
'base:monero',
'quote:usd',
'class:fx/crypto',
'ad-hoc',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'USD',
settlementAsset: { symbol: 'XYZbeta', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: null,
__typename: 'Market',
},
{
id: '6030e5b4e0ca3297a26081e5af4d453f97f96baab2d74bf56f84efcffc4c382f',
name: 'UNIDAI Monthly (30 Jun 2022)',
state: 'Active',
data: {
market: {
id: '6030e5b4e0ca3297a26081e5af4d453f97f96baab2d74bf56f84efcffc4c382f',
state: 'STATE_SUSPENDED',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'UNIDAI.MF21',
metadata: {
tags: [
'formerly:3C58ED2A4A6C5D7E',
'base:UNI',
'quote:DAI',
'class:fx/crypto',
'monthly',
'sector:defi',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'DAI',
settlementAsset: { symbol: 'tDAI', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: [
{ open: '723082', close: '726800', __typename: 'Candle' },
{
open: '726800',
close: '733551',
__typename: 'Candle',
},
{ open: '733557', close: '719960', __typename: 'Candle' },
{
open: '719961',
close: '707711',
__typename: 'Candle',
},
{ open: '702459', close: '705275', __typename: 'Candle' },
{
open: '701609',
close: '698494',
__typename: 'Candle',
},
{ open: '698494', close: '702201', __typename: 'Candle' },
{
open: '704749',
close: '704248',
__typename: 'Candle',
},
{ open: '708562', close: '714712', __typename: 'Candle' },
{
open: '718434',
close: '732567',
__typename: 'Candle',
},
{ open: '732567', close: '750475', __typename: 'Candle' },
{
open: '768916',
close: '746371',
__typename: 'Candle',
},
{ open: '740240', close: '744910', __typename: 'Candle' },
{
open: '746902',
close: '731680',
__typename: 'Candle',
},
{ open: '730156', close: '729021', __typename: 'Candle' },
{
open: '730503',
close: '738096',
__typename: 'Candle',
},
{ open: '738096', close: '743087', __typename: 'Candle' },
{
open: '739244',
close: '732352',
__typename: 'Candle',
},
{ open: '732352', close: '751259', __typename: 'Candle' },
{
open: '751259',
close: '751455',
__typename: 'Candle',
},
{ open: '751455', close: '753990', __typename: 'Candle' },
{
open: '757174',
close: '761100',
__typename: 'Candle',
},
{ open: '758974', close: '759379', __typename: 'Candle' },
{
open: '762834',
close: '761777',
__typename: 'Candle',
},
],
__typename: 'Market',
},
{
id: 'de74a5572045b300e8ec50d136896912ec76e7d7ec135bc305dfd4854d9363a4',
name: 'XMRUSD market',
state: 'Pending',
data: {
market: {
id: 'de74a5572045b300e8ec50d136896912ec76e7d7ec135bc305dfd4854d9363a4',
state: 'STATE_ACTIVE',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'XMRUSD',
metadata: {
tags: [
'base:monero',
'quote:usd',
'class:fx/crypto',
'ad-hoc',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'USD',
settlementAsset: { symbol: 'XYZbeta', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: [
{ open: '14602', close: '14596', __typename: 'Candle' },
{
open: '14596',
close: '14731',
__typename: 'Candle',
},
{ open: '14732', close: '14592', __typename: 'Candle' },
{
open: '14592',
close: '14516',
__typename: 'Candle',
},
{ open: '14516', close: '14179', __typename: 'Candle' },
{
open: '14179',
close: '14031',
__typename: 'Candle',
},
{ open: '14032', close: '14115', __typename: 'Candle' },
{
open: '14116',
close: '14166',
__typename: 'Candle',
},
{ open: '14166', close: '14377', __typename: 'Candle' },
{
open: '14377',
close: '14714',
__typename: 'Candle',
},
{ open: '14713', close: '14593', __typename: 'Candle' },
{
open: '14594',
close: '14273',
__typename: 'Candle',
},
{ open: '14272', close: '14245', __typename: 'Candle' },
{
open: '14244',
close: '14337',
__typename: 'Candle',
},
{ open: '14338', close: '14384', __typename: 'Candle' },
{
open: '14385',
close: '14257',
__typename: 'Candle',
},
{ open: '14256', close: '14105', __typename: 'Candle' },
{
open: '14106',
close: '14067',
__typename: 'Candle',
},
{ open: '14066', close: '14196', __typename: 'Candle' },
{
open: '14197',
close: '14316',
__typename: 'Candle',
},
{ open: '14315', close: '14377', __typename: 'Candle' },
{
open: '14378',
close: '14106',
__typename: 'Candle',
},
{ open: '14105', close: '14317', __typename: 'Candle' },
{
open: '14318',
close: '14467',
__typename: 'Candle',
},
],
__typename: 'Market',
},
{
id: '31ea96284611771e486c820acb26a325a99664f9854b5a7e7ad99023efa8f9e6',
name: 'ApeCoin (18 Jul 2022)',
state: 'Closed',
data: {
market: {
id: '31ea96284611771e486c820acb26a325a99664f9854b5a7e7ad99023efa8f9e6',
state: 'STATE_PROPOSED',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'APE/USD',
metadata: {
tags: [
'quote:USD',
'ticker:APE',
'class:equities/single-stock-futures',
'sector:tech',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'USD',
settlementAsset: { symbol: 'tUSDC', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: null,
__typename: 'Market',
},
{
id: '34cff959cdc2ffdb0f167820d701fe8b51cc6b8588e650d93369aaa22d6f8b74',
name: 'BTCUSD Monthly (18 Jul 2022)',
state: 'Settled',
data: {
market: {
id: '34cff959cdc2ffdb0f167820d701fe8b51cc6b8588e650d93369aaa22d6f8b74',
state: 'STATE_PROPOSED',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'BTCUSD.MF21',
metadata: {
tags: [
'formerly:076BB86A5AA41E3E',
'base:BTC',
'quote:USD',
'class:fx/crypto',
'monthly',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'USD',
settlementAsset: { symbol: 'tBTC', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: null,
__typename: 'Market',
},
{
id: '87b0bbb3c171baa5d97dfc3852332829c91e5c5dc9f7c8fb584c6d8ac75aaaf2',
name: 'Builders Club x ETHcc',
state: 'Settled',
data: {
market: {
id: '87b0bbb3c171baa5d97dfc3852332829c91e5c5dc9f7c8fb584c6d8ac75aaaf2',
state: 'STATE_ACTIVE',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'LTCUSD',
metadata: {
tags: [
'base:litecoin',
'quote:usd',
'class:fx/crypto',
'ad-hoc',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'USD',
settlementAsset: { symbol: 'XYZgamma', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: [
{ open: '5700', close: '5688', __typename: 'Candle' },
{
open: '5688',
close: '5644',
__typename: 'Candle',
},
{ open: '5644', close: '5664', __typename: 'Candle' },
{
open: '5664',
close: '5694',
__typename: 'Candle',
},
{ open: '5694', close: '5751', __typename: 'Candle' },
{
open: '5751',
close: '5853',
__typename: 'Candle',
},
{ open: '5853', close: '5773', __typename: 'Candle' },
{
open: '5773',
close: '5697',
__typename: 'Candle',
},
{ open: '5697', close: '5683', __typename: 'Candle' },
{
open: '5683',
close: '5655',
__typename: 'Candle',
},
{ open: '5655', close: '5674', __typename: 'Candle' },
{
open: '5674',
close: '5705',
__typename: 'Candle',
},
{ open: '5705', close: '5648', __typename: 'Candle' },
{
open: '5648',
close: '5646',
__typename: 'Candle',
},
{ open: '5646', close: '5687', __typename: 'Candle' },
{
open: '5687',
close: '5675',
__typename: 'Candle',
},
{ open: '5675', close: '5696', __typename: 'Candle' },
{
open: '5696',
close: '5699',
__typename: 'Candle',
},
{ open: '5699', close: '5731', __typename: 'Candle' },
{
open: '5731',
close: '5768',
__typename: 'Candle',
},
],
__typename: 'Market',
},
{
id: '45266143c6e9b58f4cff9b8906e971c531bb29ea7af01066973f9b77e8134823',
name: 'BTCUSD Monthly (18 Jul 2022)',
state: 'Pending',
data: {
market: {
id: '45266143c6e9b58f4cff9b8906e971c531bb29ea7af01066973f9b77e8134823',
state: 'STATE_PROPOSED',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'BTCUSD.MF21',
metadata: {
tags: [
'formerly:076BB86A5AA41E3E',
'base:BTC',
'quote:USD',
'class:fx/crypto',
'monthly',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'USD',
settlementAsset: { symbol: 'tBTC', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: null,
__typename: 'Market',
},
{
id: '65663ebdc96161162769c4d5c5508137416748178d7cb28e2cb0d07a151a2bc6',
name: 'ETHBTC Quarterly (30 Jun 2022)',
state: 'Active',
data: {
market: {
id: '65663ebdc96161162769c4d5c5508137416748178d7cb28e2cb0d07a151a2bc6',
state: 'STATE_ACTIVE',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'ETHBTC.QM21',
metadata: {
tags: [
'formerly:1F0BB6EB5703B099',
'base:ETH',
'quote:BTC',
'class:fx/crypto',
'quarterly',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'BTC',
settlementAsset: { symbol: 'tBTC', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: [
{ open: '6680', close: '6600', __typename: 'Candle' },
{
open: '6600',
close: '6630',
__typename: 'Candle',
},
{ open: '6630', close: '6677', __typename: 'Candle' },
{
open: '6735',
close: '6720',
__typename: 'Candle',
},
{ open: '6720', close: '6691', __typename: 'Candle' },
{
open: '6681',
close: '6730',
__typename: 'Candle',
},
{ open: '6756', close: '6778', __typename: 'Candle' },
{
open: '6778',
close: '6768',
__typename: 'Candle',
},
{ open: '6768', close: '6834', __typename: 'Candle' },
{
open: '6834',
close: '7001',
__typename: 'Candle',
},
{ open: '7001', close: '6894', __typename: 'Candle' },
{
open: '6910',
close: '6867',
__typename: 'Candle',
},
{ open: '6867', close: '6827', __typename: 'Candle' },
{
open: '6899',
close: '6910',
__typename: 'Candle',
},
{ open: '6868', close: '6902', __typename: 'Candle' },
{
open: '6905',
close: '6947',
__typename: 'Candle',
},
{ open: '6932', close: '6900', __typename: 'Candle' },
{
open: '6900',
close: '6911',
__typename: 'Candle',
},
{ open: '6936', close: '6948', __typename: 'Candle' },
{
open: '6936',
close: '6946',
__typename: 'Candle',
},
{ open: '6946', close: '6906', __typename: 'Candle' },
{
open: '6947',
close: '6962',
__typename: 'Candle',
},
{ open: '6962', close: '7027', __typename: 'Candle' },
{
open: '6941',
close: '6921',
__typename: 'Candle',
},
],
__typename: 'Market',
},
{
id: '234afabd27e3bce1a879039c041f9f00f915d98459935ddafd0169d38dd13850',
name: 'Apple Monthly (30 Jun 2022)',
state: 'Active',
data: {
market: {
id: '234afabd27e3bce1a879039c041f9f00f915d98459935ddafd0169d38dd13850',
state: 'STATE_ACTIVE',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'AAPL.MF21',
metadata: {
tags: [
'formerly:4899E01009F1A721',
'quote:USD',
'ticker:AAPL',
'class:equities/single-stock-futures',
'sector:tech',
'listing_venue:NASDAQ',
'country:US',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'USD',
settlementAsset: { symbol: 'tUSDC', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: [
{ open: '15126319', close: '15087482', __typename: 'Candle' },
{
open: '15087482',
close: '15119759',
__typename: 'Candle',
},
{ open: '15119759', close: '15061361', __typename: 'Candle' },
{
open: '15061361',
close: '14742622',
__typename: 'Candle',
},
{ open: '14742622', close: '14735571', __typename: 'Candle' },
{
open: '14735571',
close: '14694437',
__typename: 'Candle',
},
{ open: '14694437', close: '14670479', __typename: 'Candle' },
{
open: '14670479',
close: '14624796',
__typename: 'Candle',
},
{ open: '14621001', close: '14722835', __typename: 'Candle' },
{
open: '14722835',
close: '14705183',
__typename: 'Candle',
},
{ open: '14705183', close: '14710797', __typename: 'Candle' },
{
open: '14710796',
close: '14713874',
__typename: 'Candle',
},
{ open: '14713874', close: '14677982', __typename: 'Candle' },
{
open: '14677982',
close: '14710031',
__typename: 'Candle',
},
{ open: '14751685', close: '14737556', __typename: 'Candle' },
{
open: '14737556',
close: '14769139',
__typename: 'Candle',
},
{ open: '14760616', close: '14761691', __typename: 'Candle' },
{
open: '14761691',
close: '14714380',
__typename: 'Candle',
},
{ open: '14714380', close: '14740160', __typename: 'Candle' },
{
open: '14740160',
close: '14764832',
__typename: 'Candle',
},
{ open: '14764832', close: '14778059', __typename: 'Candle' },
{
open: '14761936',
close: '14707831',
__typename: 'Candle',
},
{ open: '14707831', close: '14753272', __typename: 'Candle' },
{
open: '14753272',
close: '14771411',
__typename: 'Candle',
},
],
__typename: 'Market',
},
{
id: '9f2a3c1caa67bb0773ec18d908d32b55b129b9ec2d106a8e9a87f6aa5c0375a6',
name: 'Tesla Quarterly (30 Jun 2022)',
state: 'Active',
data: {
market: {
id: '9f2a3c1caa67bb0773ec18d908d32b55b129b9ec2d106a8e9a87f6aa5c0375a6',
state: 'STATE_ACTIVE',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'TSLA.QM21',
metadata: {
tags: [
'formerly:5A86B190C384997F',
'quote:EURO',
'ticker:TSLA',
'class:equities/single-stock-futures',
'sector:tech',
'listing_venue:NASDAQ',
'country:US',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'EURO',
settlementAsset: { symbol: 'tEURO', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: [
{ open: '71263667', close: '71173749', __typename: 'Candle' },
{
open: '71173749',
close: '71055959',
__typename: 'Candle',
},
{ open: '71055959', close: '71078605', __typename: 'Candle' },
{
open: '71078605',
close: '69838205',
__typename: 'Candle',
},
{ open: '69838205', close: '69166023', __typename: 'Candle' },
{
open: '69166023',
close: '68841759',
__typename: 'Candle',
},
{ open: '68841759', close: '68711290', __typename: 'Candle' },
{
open: '68711290',
close: '68650154',
__typename: 'Candle',
},
{ open: '68644289', close: '68638322', __typename: 'Candle' },
{
open: '68704232',
close: '68343581',
__typename: 'Candle',
},
{ open: '67345721', close: '67554701', __typename: 'Candle' },
{
open: '67533143',
close: '67551571',
__typename: 'Candle',
},
{ open: '67533286', close: '67543539', __typename: 'Candle' },
{
open: '67580208',
close: '67472337',
__typename: 'Candle',
},
{ open: '67416289', close: '67459697', __typename: 'Candle' },
{
open: '67396085',
close: '67528265',
__typename: 'Candle',
},
{ open: '67491799', close: '67538833', __typename: 'Candle' },
{
open: '67493210',
close: '67362908',
__typename: 'Candle',
},
{ open: '67362908', close: '67518182', __typename: 'Candle' },
{
open: '67518182',
close: '67635775',
__typename: 'Candle',
},
{ open: '67635775', close: '67734861', __typename: 'Candle' },
{
open: '67714943',
close: '67736742',
__typename: 'Candle',
},
{ open: '67716074', close: '67690826', __typename: 'Candle' },
{
open: '67714352',
close: '67817444',
__typename: 'Candle',
},
],
__typename: 'Market',
},
{
id: '8a45ee934d3ddac4b036f9884df1064a5353c620a56f775ba36597d0edef9a7a',
name: 'Go big or Go home',
state: 'Active',
data: {
market: {
id: '8a45ee934d3ddac4b036f9884df1064a5353c620a56f775ba36597d0edef9a7a',
state: 'STATE_SUSPENDED',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'LTCUSD',
metadata: {
tags: [
'base:litecoin',
'quote:usd',
'class:fx/crypto',
'ad-hoc',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'USD',
settlementAsset: { symbol: 'XYZgamma', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: [
{ open: '5809', close: '5795', __typename: 'Candle' },
{
open: '5795',
close: '5845',
__typename: 'Candle',
},
{ open: '5845', close: '5779', __typename: 'Candle' },
{
open: '5779',
close: '5710',
__typename: 'Candle',
},
{ open: '5710', close: '5691', __typename: 'Candle' },
],
__typename: 'Market',
},
{
id: 'aede7b9ac0c3b225004929c5455160a00f59864aad32ec366e8a2bff1b30fd0f',
name: 'BTCUSD Monthly (08 Jul 2022)',
state: 'Active',
data: {
market: {
id: 'aede7b9ac0c3b225004929c5455160a00f59864aad32ec366e8a2bff1b30fd0f',
state: 'STATE_PROPOSED',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'BTCUSD.MF21',
metadata: {
tags: [
'formerly:076BB86A5AA41E3E',
'base:BTC',
'quote:USD',
'class:fx/crypto',
'monthly',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'USD',
settlementAsset: { symbol: 'tBTC', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: null,
__typename: 'Market',
},
{
id: '9398707e01daa1a1f1ca6ff87cf8d6c03fe7373ce31121ce81b99a129e6bda47',
name: 'BTCUSD Monthly (18 Jul 2022)',
state: 'Active',
data: {
market: {
id: '9398707e01daa1a1f1ca6ff87cf8d6c03fe7373ce31121ce81b99a129e6bda47',
state: 'STATE_PROPOSED',
__typename: 'Market',
},
__typename: 'MarketData',
},
tradableInstrument: {
instrument: {
code: 'BTCUSD.MF21',
metadata: {
tags: [
'formerly:076BB86A5AA41E3E',
'base:BTC',
'quote:USD',
'class:fx/crypto',
'monthly',
'sector:crypto',
],
__typename: 'InstrumentMetadata',
},
product: {
__typename: 'Future',
quoteName: 'USD',
settlementAsset: { symbol: 'tBTC', __typename: 'Asset' },
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
candles: null,
__typename: 'Market',
},
],
};
};
export const generateLongListMarkets = (count: number) => {
const markets = [];
for (let i = 0; i < count; i++) {
const { id, name } = protoMarket;
markets.push({
...protoMarket,
id: id + i,
name: name + i,
data: {
...protoMarket.data,
id: id + i,
},
});
}
return { markets };
};
@@ -0,0 +1,57 @@
export const generatePartyBalance = () => {
return {
party: {
accounts: [
{
balance: '88474051',
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'Account',
},
{
balance: '100000000',
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
symbol: 'tEURO',
name: 'tEURO TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'Account',
},
{
balance: '3412867',
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'Account',
},
{
balance: '70007',
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'Account',
},
],
__typename: 'Party',
},
};
};
@@ -0,0 +1,19 @@
export const generatePartyMarketData = () => {
return {
party: {
id: '2e1ef32e5804e14232406aebaad719087d326afa5c648b7824d0823d8a46c8d1',
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',
},
};
};
+10
View File
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"sourceMap": false,
"outDir": "../../dist/out-tsc",
"allowJs": true,
"types": ["cypress", "node", "cypress-real-events"]
},
"include": ["src/**/*.ts", "src/**/*.js"]
}
@@ -13,4 +13,4 @@ last 2 Edge major versions
last 2 Safari major version
last 2 iOS major versions
Firefox ESR
not IE 9-11 # For IE 9-11 support, remove 'not'.
not IE 9-11 # For IE 9-11 support, remove 'not'.
@@ -20,8 +20,8 @@ NX_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
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
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://stagnet1.console.vega.xyz\",\"STAGNET3\":\"https://stagnet3.console.vega.xyz\"}
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
@@ -1,3 +1,4 @@
# App configuration variables
NX_VEGA_URL=http://localhost:3028/query
NX_VEGA_ENV=LOCAL
NX_VEGA_REST=http://localhost:3029
+9
View File
@@ -0,0 +1,9 @@
# App configuration variables
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_REST=https://api.n04.d.vega.xyz
NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\"}
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
@@ -1,8 +1,9 @@
# App configuration variables
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/mainnet-network.json
NX_VEGA_URL=https://api.vega.xyz/query
NX_VEGA_URL=https://api.token.vega.xyz/query
NX_VEGA_ENV=MAINNET
NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\",\"TESTNET\":\"https://console.fairground.wtf\"}
NX_VEGA_REST=https://api.token.vega.xyz
NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://etherscan.io
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz
+8
View File
@@ -0,0 +1,8 @@
# App configuration variables
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json
NX_VEGA_URL=https://api.n01.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET3
NX_VEGA_REST=https://api.n01.stagnet3.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,7 +2,8 @@
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json
NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
NX_VEGA_ENV=TESTNET
NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\",\"TESTNET\":\"https://console.fairground.wtf\"}
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_REST=https://api.n11.testnet.vega.xyz
NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
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
@@ -1,6 +1,6 @@
{
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
"ignorePatterns": ["!**/*", "__generated__"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
@@ -1,11 +1,11 @@
/* eslint-disable */
export default {
displayName: 'liquidity-provision-dashboard',
module.exports = {
displayName: 'console-lite',
preset: '../../jest.preset.js',
transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/next/babel'] }],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/apps/liquidity-provision-dashboard',
coverageDirectory: '../../coverage/apps/console-lite',
setupFilesAfterEnv: ['./setup-tests.ts'],
};
+83
View File
@@ -0,0 +1,83 @@
{
"root": "apps/console-lite",
"sourceRoot": "apps/console-lite/src",
"projectType": "application",
"targets": {
"build": {
"executor": "./tools/executors/webpack:build",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"compiler": "babel",
"outputPath": "dist/apps/console-lite",
"index": "apps/console-lite/src/index.html",
"baseHref": "/",
"main": "apps/console-lite/src/main.tsx",
"polyfills": "apps/console-lite/src/polyfills.ts",
"tsConfig": "apps/console-lite/tsconfig.app.json",
"assets": [
"apps/console-lite/src/favicon.ico",
"apps/console-lite/src/assets"
],
"styles": ["apps/console-lite/src/styles.scss"],
"scripts": [],
"webpackConfig": "@nrwl/react/plugins/webpack"
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "apps/console-lite/src/environments/environment.ts",
"with": "apps/console-lite/src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false
}
}
},
"serve": {
"executor": "./tools/executors/webpack:serve",
"options": {
"buildTarget": "console-lite:build",
"hmr": true,
"port": 4001
},
"configurations": {
"production": {
"buildTarget": "console-lite:build:production",
"hmr": false
}
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/console-lite/**/*.{ts,tsx,js,jsx}"]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["coverage/apps/console-lite"],
"options": {
"jestConfig": "apps/console-lite/jest.config.js",
"passWithNoTests": true
}
},
"build-netlify": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"commands": [
"cp apps/console-lite/netlify.toml netlify.toml",
"nx build console-lite"
]
}
}
},
"tags": []
}
+18
View File
@@ -0,0 +1,18 @@
import '@testing-library/jest-dom';
import { defaultFallbackInView } from 'react-intersection-observer';
defaultFallbackInView(true);
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
+62
View File
@@ -0,0 +1,62 @@
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { createClient } from './lib/apollo-client';
import { ThemeContext } from '@vegaprotocol/react-helpers';
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
import { EnvironmentProvider, NetworkLoader } from '@vegaprotocol/environment';
import {
VegaConnectDialog,
VegaManageDialog,
VegaWalletProvider,
} from '@vegaprotocol/wallet';
import { Connectors } from './lib/vega-connectors';
import '../styles.scss';
import { AppLoader } from './components/app-loader';
import Header from './components/header';
import { Main } from './components/main';
import LocalContext from './context/local-context';
import useLocalValues from './hooks/use-local-values';
function App() {
const [theme, toggleTheme] = useThemeSwitcher();
const localValues = useLocalValues(toggleTheme);
const {
vegaWalletDialog,
menu: { setMenuOpen },
} = localValues;
const location = useLocation();
useEffect(() => {
setMenuOpen(false);
}, [location, setMenuOpen]);
return (
<EnvironmentProvider>
<ThemeContext.Provider value={theme}>
<NetworkLoader createClient={createClient}>
<VegaWalletProvider>
<LocalContext.Provider value={localValues}>
<AppLoader>
<div className="max-h-full min-h-full dark:bg-lite-black dark:text-white-60 bg-white text-black-60 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>
</ThemeContext.Provider>
</EnvironmentProvider>
);
}
export default App;
@@ -0,0 +1,19 @@
import { useEagerConnect } from '@vegaprotocol/wallet';
import type { ReactNode } from 'react';
import { Connectors } from '../../lib/vega-connectors';
interface AppLoaderProps {
children: ReactNode;
}
/**
* Component to handle any app initialization, startup querys and other things
* that must happen for it can be used
*/
export function AppLoader({ children }: AppLoaderProps) {
// Get keys from vega wallet immediately
useEagerConnect(Connectors);
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{children}</>;
}
@@ -0,0 +1,51 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: MarketTags
// ====================================================
export interface MarketTags_market_tradableInstrument_instrument_metadata {
__typename: "InstrumentMetadata";
/**
* An arbitrary list of tags to associated to associate to the Instrument (string list)
*/
tags: string[] | null;
}
export interface MarketTags_market_tradableInstrument_instrument {
__typename: "Instrument";
/**
* Metadata for this instrument
*/
metadata: MarketTags_market_tradableInstrument_instrument_metadata;
}
export interface MarketTags_market_tradableInstrument {
__typename: "TradableInstrument";
/**
* An instance of, or reference to, a fully specified instrument.
*/
instrument: MarketTags_market_tradableInstrument_instrument;
}
export interface MarketTags_market {
__typename: "Market";
/**
* An instance of, or reference to, a tradable instrument.
*/
tradableInstrument: MarketTags_market_tradableInstrument;
}
export interface MarketTags {
/**
* An instrument that is trading on the Vega network
*/
market: MarketTags_market | null;
}
export interface MarketTagsVariables {
marketId: string;
}
@@ -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;
}
@@ -0,0 +1,36 @@
import React from 'react';
import Video from '../header/video';
import Comet from '../header/comet';
import Star from '../icons/star';
const Baubles = () => {
return (
<aside className="relative right-0 top-0 h-[700px] hidden md:block md:w-1/2 overflow-hidden">
<div className="absolute top-[100px] w-[393px] left-[19%] h-[517px]">
<div className="absolute top-[82px] right-[34px] w-[100px] h-[100px] clip-path-rounded">
<Video />
</div>
<div className="absolute bottom-[100px] left-[59px] w-[200px] h-[200px] clip-path-rounded">
<Video />
</div>
<div className="absolute w-[118px] h-[85px] right-0 bottom-[178px]">
<Comet />
</div>
<div className="absolute w-[118px] h-[82px] left-0 bottom-[120px]">
<Comet />
</div>
<div className="absolute w-[20px] h-[20px] top-0 left-[49px]">
<Star />
</div>
<div className="absolute w-[20px] h-[20px] top-[89px] left-[184px]">
<Star />
</div>
<div className="absolute w-[10px] h-[10px] bottom-0 right-[137px]">
<Star />
</div>
</div>
</aside>
);
};
export default Baubles;
@@ -15,23 +15,3 @@ export const NOTIONAL_SIZE_TOOLTIP_TEXT = t(
export const EST_FEES_TOOLTIP_TEXT = t(
'When you execute a new buy or sell order, you must pay a small amount of commission to the network for doing so. This fee is used to provide income to the node operates of the network and market makers who make prices on the futures market you are trading.'
);
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 SummaryValidationType {
NoCollateral = 'NoCollateral',
TradingMode = 'MarketTradingMode',
MarketState = 'MarketState',
}
@@ -0,0 +1,67 @@
import React from 'react';
import { render } from '@testing-library/react';
import type {
PartyBalanceQuery_party_accounts,
PartyBalanceQuery_party_accounts_asset,
} from './__generated__/PartyBalanceQuery';
import { DealTicketBalance } from './deal-ticket-balance';
import { AccountType } from '@vegaprotocol/types';
const tDAI: PartyBalanceQuery_party_accounts_asset = {
__typename: 'Asset',
id: '1',
symbol: 'tDAI',
name: 'TDAI',
decimals: 2,
};
const accounts: PartyBalanceQuery_party_accounts[] = [
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '1000000',
asset: tDAI,
},
];
describe('DealTicketBalance', function () {
it('should render the balance', () => {
const { getByText, getByRole } = render(
<DealTicketBalance
settlementAsset={tDAI}
accounts={accounts}
isWalletConnected
/>
);
expect(getByRole('complementary')).toHaveAccessibleName('tDAI Balance');
expect(getByText('10,000.00')).toBeInTheDocument();
expect(getByText('tDAI')).toBeInTheDocument();
});
it('should prompt to connect wallet', () => {
const { getByText } = render(
<DealTicketBalance
settlementAsset={tDAI}
accounts={accounts}
isWalletConnected={false}
/>
);
expect(
getByText('Please connect your Vega wallet to see your balance')
).toBeInTheDocument();
});
it('should display zero balance', () => {
const { getByText } = render(
<DealTicketBalance
settlementAsset={tDAI}
accounts={[]}
isWalletConnected={true}
/>
);
expect(getByText('No tDAI left to trade')).toBeInTheDocument();
});
});
@@ -0,0 +1,62 @@
import * as React from 'react';
import classNames from 'classnames';
import type { DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset } 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 { AccountType } from '@vegaprotocol/types';
interface DealTicketBalanceProps {
settlementAsset: DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset;
accounts: PartyBalanceQuery_party_accounts[];
isWalletConnected: boolean;
className?: string;
}
export const DealTicketBalance = ({
settlementAsset,
accounts,
isWalletConnected,
className = '',
}: DealTicketBalanceProps) => {
const settlementAssetId = settlementAsset?.id;
const settlementAssetSymbol = settlementAsset?.symbol;
const settlementAccount = useSettlementAccount(
settlementAssetId,
accounts,
AccountType.ACCOUNT_TYPE_GENERAL
);
const formatedNumber =
settlementAccount?.balance &&
settlementAccount.asset.decimals &&
addDecimalsFormatNumber(
settlementAccount.balance,
settlementAccount.asset.decimals
);
const balance = (
<p className="text-blue text-lg font-semibold">
{settlementAccount
? t(`${formatedNumber}`)
: `No ${settlementAssetSymbol} left to trade`}
</p>
);
const connectWallet = (
<p>{t('Please connect your Vega wallet to see your balance')}</p>
);
const ariaLabel = t(`${settlementAssetSymbol} Balance`);
return (
<aside
aria-label={ariaLabel}
className={classNames('text-right', className)}
>
<div className="inline-block">
<span className="text-blue">{settlementAssetSymbol}</span>
{isWalletConnected ? balance : connectWallet}
</div>
</aside>
);
};
@@ -0,0 +1,86 @@
import * as React from 'react';
import { useParams } from 'react-router-dom';
import { gql, useQuery } from '@apollo/client';
import {
DealTicketManager,
DealTicketContainer as Container,
} from '@vegaprotocol/deal-ticket';
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';
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 { keypair } = useVegaWallet();
const { data: partyData, loading } = useQuery<PartyBalanceQuery>(
PARTY_BALANCE_QUERY,
{
variables: { partyId: keypair?.pub },
skip: !keypair?.pub,
}
);
const loader = <Loader />;
const container = marketId ? (
<Container marketId={marketId}>
{(data) => {
const balance = (
<DealTicketBalance
className="mb-16"
settlementAsset={
data.market.tradableInstrument.instrument.product?.settlementAsset
}
accounts={partyData?.party?.accounts || []}
isWalletConnected={!!keypair?.pub}
/>
);
return (
<DealTicketManager market={data.market}>
{loading ? loader : balance}
<DealTicketSteps market={data.market} partyData={partyData} />
</DealTicketManager>
);
}}
</Container>
) : (
tempEmptyText
);
return (
<section className="flex">
<section className="w-full md:w-1/2 md:min-w-[500px]">
{keypair ? container : <ConnectWallet />}
</section>
<Baubles />
</section>
);
};
@@ -1,9 +1,9 @@
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';
interface DealTicketEstimatesProps {
quoteName?: string;
@@ -13,91 +13,14 @@ interface DealTicketEstimatesProps {
fees?: string;
notionalSize?: string;
size?: string;
slippage?: string;
}
export const DealTicketEstimates = ({
price,
quoteName,
estCloseOut,
estMargin,
fees,
notionalSize,
size,
slippage,
}: DealTicketEstimatesProps) => (
<dl className="text-black dark:text-white">
{size && (
<div className="flex justify-between mb-2">
<DataTitle>{t('Contracts')}</DataTitle>
<ValueTooltipRow
value={size}
description={constants.CONTRACTS_MARGIN_TOOLTIP_TEXT}
id="contracts_tooltip_trigger"
/>
</div>
)}
{price && (
<div className="flex justify-between mb-2">
<DataTitle>{t('Est. Price')}</DataTitle>
<dd>{price}</dd>
</div>
)}
{notionalSize && (
<div className="flex justify-between mb-2">
<DataTitle quoteName={quoteName}>{t('Est. Position Size')}</DataTitle>
<ValueTooltipRow
value={notionalSize}
description={constants.NOTIONAL_SIZE_TOOLTIP_TEXT}
/>
</div>
)}
{fees && (
<div className="flex justify-between mb-2">
<DataTitle quoteName={quoteName}>{t('Est. Fees')}</DataTitle>
<ValueTooltipRow
value={fees}
description={constants.EST_FEES_TOOLTIP_TEXT}
/>
</div>
)}
{estMargin && (
<div className="flex justify-between mb-2">
<DataTitle quoteName={quoteName}>{t('Est. Margin')}</DataTitle>
<ValueTooltipRow
value={estMargin}
description={constants.EST_MARGIN_TOOLTIP_TEXT}
/>
</div>
)}
{estCloseOut && (
<div className="flex justify-between mb-2">
<DataTitle quoteName={quoteName}>{t('Est. Close out')}</DataTitle>
<ValueTooltipRow
value={estCloseOut}
description={constants.EST_CLOSEOUT_TOOLTIP_TEXT}
/>
</div>
)}
{slippage && (
<div className="flex justify-between mb-2">
<DataTitle>{t('Est. Price Impact / Slippage')}</DataTitle>
<ValueTooltipRow description={constants.EST_SLIPPAGE}>
<TrafficLight value={parseFloat(slippage)} q1={1} q2={5}>
{slippage}%
</TrafficLight>
</ValueTooltipRow>
</div>
)}
</dl>
);
interface DataTitleProps {
children: ReactNode;
quoteName?: string;
}
export const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
<dt>
{children}
{quoteName && <small> ({quoteName})</small>}
@@ -105,20 +28,14 @@ export const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
);
interface ValueTooltipProps {
value?: string;
children?: ReactNode;
value: string;
description: string;
id?: string;
}
export const ValueTooltipRow = ({
value,
children,
description,
id,
}: ValueTooltipProps) => (
<dd className="flex gap-x-2 items-center">
{value || children}
const ValueTooltipRow = ({ value, description, id }: ValueTooltipProps) => (
<dd className="flex gap-x-5 items-center">
{value}
<Tooltip align="center" description={description}>
<div className="cursor-help" id={id || ''} tabIndex={-1}>
<Icon
@@ -130,3 +47,72 @@ export const ValueTooltipRow = ({
</Tooltip>
</dd>
);
export const DealTicketEstimates = ({
price,
quoteName,
estCloseOut,
estMargin,
fees,
notionalSize,
size,
}: DealTicketEstimatesProps) => (
<dl className="text-black dark:text-white">
{size && (
<div className="flex justify-between mb-8">
<DataTitle>{t('Contracts')}</DataTitle>
<ValueTooltipRow
value={size}
description={constants.CONTRACTS_MARGIN_TOOLTIP_TEXT}
id="contracts_tooltip_trigger"
/>
</div>
)}
{price && (
<div className="flex justify-between mb-8">
<DataTitle>{t('Est. Price')}</DataTitle>
<dd>{price}</dd>
</div>
)}
{notionalSize && (
<div className="flex justify-between mb-8">
<DataTitle quoteName={quoteName}>{t('Est. Position Size')}</DataTitle>
<ValueTooltipRow
value={notionalSize}
description={constants.NOTIONAL_SIZE_TOOLTIP_TEXT}
/>
</div>
)}
{fees && (
<div className="flex justify-between mb-8">
<DataTitle quoteName={quoteName}>{t('Est. Fees')}</DataTitle>
<ValueTooltipRow
value={fees}
description={constants.EST_FEES_TOOLTIP_TEXT}
/>
</div>
)}
{estMargin && (
<div className="flex justify-between mb-8">
<DataTitle quoteName={quoteName}>{t('Est. Margin')}</DataTitle>
<ValueTooltipRow
value={estMargin}
description={constants.EST_MARGIN_TOOLTIP_TEXT}
/>
</div>
)}
{estCloseOut && (
<div className="flex justify-between">
<dt>
<span>{t('Est. Close out')}</span>
&nbsp;
<small>({quoteName})</small>
</dt>
<ValueTooltipRow
value={estCloseOut}
description={constants.EST_CLOSEOUT_TOOLTIP_TEXT}
/>
</div>
)}
</dl>
);
@@ -0,0 +1,201 @@
import React, { useCallback, useState } from 'react';
import { t } from '@vegaprotocol/react-helpers';
import {
SliderRoot,
SliderThumb,
SliderTrack,
SliderRange,
Button,
Input,
FormGroup,
} from '@vegaprotocol/ui-toolkit';
import { BigNumber } from 'bignumber.js';
import { DealTicketEstimates } from './deal-ticket-estimates';
interface DealTicketSizeProps {
step: number;
min: number;
max: number;
value: number;
onValueChange: (value: number[]) => void;
name: string;
quoteName: string;
price: string;
estCloseOut: string;
estMargin: string;
fees: string;
positionDecimalPlaces: number;
notionalSize: string;
}
const getSizeLabel = (value: number): string => {
const MIN_LABEL = 'Min';
const MAX_LABEL = 'Max';
if (value === 0) {
return MIN_LABEL;
} else if (value === 100) {
return MAX_LABEL;
}
return `${value}%`;
};
export const DealTicketSize = ({
value,
step,
min,
max,
price,
quoteName,
onValueChange,
estCloseOut,
positionDecimalPlaces,
fees,
notionalSize,
}: DealTicketSizeProps) => {
const sizeRatios = [0, 25, 50, 75, 100];
const [inputValue, setInputValue] = useState(value);
const [isInputVisible, setIsInputVisible] = useState(false);
const onInputValueChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
const value = parseFloat(event.target.value);
const isLessThanMin = value < min;
const isMoreThanMax = value > max;
if (value) {
if (isLessThanMin) {
onValueChange([min]);
} else if (isMoreThanMax) {
onValueChange([max]);
} else {
onValueChange([value]);
}
}
setInputValue(value);
},
[min, max, onValueChange, setInputValue]
);
const onButtonValueChange = useCallback(
(size: number) => {
if (isInputVisible) {
setIsInputVisible(false);
}
const newVal = new BigNumber(size)
.decimalPlaces(positionDecimalPlaces)
.toNumber();
onValueChange([newVal]);
setInputValue(newVal);
},
[isInputVisible, onValueChange, positionDecimalPlaces]
);
const toggleInput = useCallback(() => {
setIsInputVisible(!isInputVisible);
}, [isInputVisible]);
const onInputEnter = useCallback(
(event: React.KeyboardEvent) => {
if (event.key === 'Enter') {
event.stopPropagation();
toggleInput();
}
},
[toggleInput]
);
return max === 0 ? (
<p>Not enough balance to trade</p>
) : (
<div>
<div className="flex justify-between text-black dark:text-white mb-8">
<span data-testid="min-label">{min}</span>
<span data-testid="max-label">{max}</span>
</div>
<SliderRoot
className="mb-8"
value={[value]}
onValueChange={onValueChange}
step={step}
min={min}
max={max}
>
<SliderTrack className="bg-lightGrey dark:bg-offBlack">
<SliderRange className="!bg-black dark:!bg-white" />
</SliderTrack>
<SliderThumb />
</SliderRoot>
<div
data-testid="percentage-selector"
className="flex w-full justify-between text-black dark:text-white mb-32"
>
{sizeRatios.map((size, index) => {
const proportionalSize = size ? (size / 100) * max : min;
return (
<Button
variant="inline-link"
className="no-underline !text-blue"
onClick={() => onButtonValueChange(proportionalSize)}
key={index}
>
{getSizeLabel(size)}
</Button>
);
})}
</div>
<dl className="text-black dark:text-white">
<div className="flex items-center justify-between mb-8">
<dt>{t('Contracts')}</dt>
<dd className="flex justify-end w-full">
<FormGroup
className="mb-0 flex items-center"
labelClassName="mr-8 sr-only"
label="Enter Size"
labelFor="trade-size-input"
>
{isInputVisible ? (
<>
<Input
id="input-order-size-market"
type="number"
step={step}
min={min}
max={max}
className="w-full"
value={inputValue}
onKeyDown={onInputEnter}
onChange={onInputValueChange}
/>
<Button
variant="inline-link"
className="no-underline !text-blue"
onClick={toggleInput}
>
{t('set')}
</Button>
</>
) : (
<Button
variant="inline-link"
className="no-underline !text-blue"
onClick={toggleInput}
>
{value}
</Button>
)}
</FormGroup>
</dd>
</div>
</dl>
<DealTicketEstimates
quoteName={quoteName}
fees={fees}
estCloseOut={estCloseOut}
price={price}
notionalSize={notionalSize}
/>
</div>
);
};
@@ -0,0 +1,253 @@
import React, { useCallback, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useForm, Controller } from 'react-hook-form';
import { Stepper } from '../stepper';
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
import { InputError } from '@vegaprotocol/ui-toolkit';
import { BigNumber } from 'bignumber.js';
import {
getOrderDialogTitle,
getOrderDialogIntent,
getOrderDialogIcon,
MarketSelector,
} from '@vegaprotocol/deal-ticket';
import type { Order } from '@vegaprotocol/orders';
import { useVegaWallet, VegaTxStatus } from '@vegaprotocol/wallet';
import { t, addDecimal, toDecimal } from '@vegaprotocol/react-helpers';
import {
getDefaultOrder,
useOrderValidation,
useOrderSubmit,
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 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';
interface DealTicketMarketProps {
market: DealTicketQuery_market;
partyData?: PartyBalanceQuery;
}
export const DealTicketSteps = ({
market,
partyData,
}: DealTicketMarketProps) => {
const navigate = useNavigate();
const setMarket = useCallback(
(marketId: string) => {
navigate(`/trading/${marketId}`);
},
[navigate]
);
const {
control,
handleSubmit,
watch,
setValue,
formState: { errors },
} = useForm<Order>({
mode: 'onChange',
defaultValues: getDefaultOrder(market),
});
const [max, setMax] = useState<number | null>(null);
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 estCloseOut = useOrderCloseOut({ order, market, partyData });
const { keypair } = useVegaWallet();
const estMargin = useOrderMargin({
order,
market,
partyId: keypair?.pub || '',
});
const value = new BigNumber(orderSize).toNumber();
const price =
market.depth.lastTrade &&
addDecimal(market.depth.lastTrade.price, market.decimalPlaces);
const emptyString = ' - ';
const [notionalSize, setNotionalSize] = useState<string | null>(null);
const [fees, setFees] = useState<string | null>(null);
const maxTrade = useMaximumPositionSize({
partyId: keypair?.pub || '',
accounts: partyData?.party?.accounts || [],
marketId: market.id,
settlementAssetId:
market.tradableInstrument.instrument.product.settlementAsset.id,
price: market?.depth?.lastTrade?.price,
order,
});
useEffect(() => {
setMax(
new BigNumber(maxTrade)
.decimalPlaces(market.positionDecimalPlaces)
.toNumber()
);
}, [maxTrade, market.positionDecimalPlaces]);
const { message: invalidText, isDisabled } = useOrderValidation({
market,
orderType,
orderTimeInForce,
fieldErrors: errors,
});
const { submit, transaction, finalizedOrder, TransactionDialog } =
useOrderSubmit(market);
const onSizeChange = (value: number[]) => {
const newVal = new BigNumber(value[0])
.decimalPlaces(market.positionDecimalPlaces)
.toString();
const isValid = validateSize(step)(newVal);
if (isValid !== 'step') {
setValue('size', newVal);
}
};
useEffect(() => {
if (market?.depth?.lastTrade?.price) {
const size = new BigNumber(market.depth.lastTrade.price)
.multipliedBy(value)
.toNumber();
setNotionalSize(addDecimal(size, market.decimalPlaces));
}
}, [market, value]);
useEffect(() => {
if (estMargin?.fees && notionalSize) {
const percentage = new BigNumber(estMargin?.fees)
.dividedBy(notionalSize)
.multipliedBy(100)
.decimalPlaces(2)
.toString();
setFees(`${estMargin.fees} (${percentage}%)`);
}
}, [estMargin, notionalSize]);
const transactionStatus =
transaction.status === VegaTxStatus.Requested ||
transaction.status === VegaTxStatus.Pending
? 'pending'
: 'default';
const onSubmit = React.useCallback(
(order: Order) => {
if (transactionStatus !== 'pending') {
submit(order);
}
},
[transactionStatus, submit]
);
const steps = [
{
label: t('Select Market'),
component: (
<MarketSelector
market={market}
setMarket={setMarket}
ItemRenderer={MarketNameRenderer}
/>
),
value: market.name,
},
{
label: t('Select Direction'),
component: (
<Controller
name="side"
control={control}
render={({ field }) => (
<SideSelector value={field.value} onSelect={field.onChange} />
)}
/>
),
value: SIDE_NAMES[orderSide] || '',
},
{
label: t('Choose Position Size'),
component:
max !== null ? (
<DealTicketSize
step={step}
min={step}
max={max}
onValueChange={onSizeChange}
value={new BigNumber(orderSize).toNumber()}
name="size"
price={price || emptyString}
positionDecimalPlaces={market.positionDecimalPlaces}
quoteName={
market.tradableInstrument.instrument.product.settlementAsset
.symbol
}
notionalSize={notionalSize || emptyString}
estCloseOut={estCloseOut}
fees={fees || emptyString}
estMargin={estMargin?.margin || emptyString}
/>
) : (
'loading...'
),
value: orderSize,
},
{
label: t('Review Trade'),
component: (
<div className="mb-8">
{invalidText && (
<InputError className="mb-8" data-testid="dealticket-error-message">
{invalidText}
</InputError>
)}
<ReviewTrade
market={market}
isDisabled={isDisabled}
transactionStatus={transactionStatus}
order={order}
estCloseOut={estCloseOut}
estMargin={estMargin?.margin || emptyString}
price={price || emptyString}
quoteName={
market.tradableInstrument.instrument.product.settlementAsset
.symbol
}
notionalSize={notionalSize || emptyString}
fees={fees || emptyString}
/>
<TransactionDialog
title={getOrderDialogTitle(finalizedOrder?.status)}
intent={getOrderDialogIntent(finalizedOrder?.status)}
icon={getOrderDialogIcon(finalizedOrder?.status)}
>
<OrderFeedback transaction={transaction} order={finalizedOrder} />
</TransactionDialog>
</div>
),
disabled: true,
},
];
return (
<form onSubmit={handleSubmit(onSubmit)} className="px-4 py-8">
<Stepper steps={steps} />
</form>
);
};
@@ -0,0 +1,2 @@
export * from './deal-ticket-container';
export * from './deal-ticket-size';
@@ -0,0 +1,123 @@
import { t } from '@vegaprotocol/react-helpers';
import {
Button,
KeyValueTable,
KeyValueTableRow,
} from '@vegaprotocol/ui-toolkit';
import * as React from 'react';
import classNames from 'classnames';
import type { DealTicketQuery_market } 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 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!) {
market(id: $marketId) {
tradableInstrument {
instrument {
metadata {
tags
}
}
}
}
}
`;
interface Props {
market: DealTicketQuery_market;
isDisabled: boolean;
transactionStatus?: string;
order: Order;
estCloseOut: string;
estMargin: string;
quoteName: string;
price: string;
fees: string;
notionalSize: string;
}
export default ({
isDisabled,
market,
order,
transactionStatus,
estCloseOut,
quoteName,
fees,
price,
notionalSize,
}: Props) => {
const { data: tagsData } = useQuery<MarketTags, MarketTagsVariables>(
MARKET_TAGS_QUERY,
{
variables: { marketId: market.id },
}
);
return (
<div className="mb-8 text-black dark:text-white" data-testid="review-trade">
<KeyValueTable>
<KeyValueTableRow noBorder>
<div className="flex flex-none gap-x-5 items-center">
<div
className={classNames(
{
'buyButton dark:buyButtonDark': order.side === Side.SIDE_BUY,
'sellButton dark:sellButtonDark':
order.side === Side.SIDE_SELL,
},
'px-8 py-4 inline text-ui-small'
)}
>
{SIDE_NAMES[order.side]}
</div>
<div>{market.tradableInstrument.instrument.product.quoteName}</div>
<div>
{tagsData?.market?.tradableInstrument.instrument.metadata
.tags && (
<SimpleMarketExpires
tags={
tagsData?.market.tradableInstrument.instrument.metadata.tags
}
/>
)}
</div>
</div>
<div className="text-blue">
{`@ ${price} `}
<span className="text-ui-small inline">(EST)</span>
</div>
</KeyValueTableRow>
</KeyValueTable>
<DealTicketEstimates
size={order.size}
quoteName={quoteName}
fees={fees}
estCloseOut={estCloseOut}
notionalSize={notionalSize}
/>
<Button
className="w-full !py-8 mt-64 max-w-sm"
boxShadow={false}
variant="secondary"
type="submit"
disabled={transactionStatus === 'pending' || isDisabled}
data-testid="place-order"
appendIconName="arrow-top-right"
>
{transactionStatus === 'pending' ? t('Pending...') : t('Submit')}
</Button>
</div>
);
};
@@ -0,0 +1,60 @@
import React from 'react';
import classNames from 'classnames';
import { FormGroup, Button } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers';
import { Side } from '@vegaprotocol/types';
interface SideSelectorProps {
value: Side;
onSelect: (side: Side) => void;
}
export const SIDE_NAMES: Record<Side, string> = {
[Side.SIDE_BUY]: t('Long'),
[Side.SIDE_SELL]: t('Short'),
};
export default ({ value, onSelect }: SideSelectorProps) => {
return (
<FormGroup
label={t('Direction')}
labelFor="order-side-toggle"
labelClassName="sr-only"
>
<fieldset
className="w-full grid md:grid-cols-2 gap-20"
id="order-side-toggle"
>
<Button
variant="inline-link"
aria-label={t('Open long position')}
className={classNames(
'py-8',
'buyButton hover:buyButton dark:buyButtonDark dark:hover:buyButtonDark',
{ selected: value === Side.SIDE_BUY }
)}
onClick={() => onSelect(Side.SIDE_BUY)}
>
{t('Long')}
</Button>
<Button
variant="inline-link"
aria-label={t('Open short position')}
className={classNames(
'py-8',
'sellButton hover:sellButton dark:sellButtonDark dark:hover:sellButtonDark',
{ selected: value === Side.SIDE_SELL }
)}
onClick={() => onSelect(Side.SIDE_SELL)}
>
{t('Short')}
</Button>
<div className="md:col-span-2 text-black dark:text-white text-ui-small">
{t(
'Trading derivatives allows you to make a profit or loss regardless of whether the market you are trading goes up or down. If you open a "long" position, you will make a profit if the price of your chosen market goes up, and you will make a profit for "short" positions when the price goes down.'
)}
</div>
</fieldset>
</FormGroup>
);
};
@@ -0,0 +1,21 @@
import * as React from 'react';
import classNames from 'classnames';
import type { ReactElement } from 'react';
interface Props {
children: ReactElement | ReactElement[];
className?: string;
}
export const DrawerContent = ({ children, className = '' }: Props) => {
const classes = classNames(
'w-full sm:w-full grow-1 p-12 md:p-20 overflow-hidden',
className
);
return (
<main aria-label="Page Content" className={classes}>
{children}
</main>
);
};
@@ -0,0 +1,49 @@
import * as React from 'react';
import classNames from 'classnames';
import { Button, Icon } from '@vegaprotocol/ui-toolkit';
import { IconNames } from '@blueprintjs/icons';
import type { IconName } from '@vegaprotocol/ui-toolkit';
import { useEffect, useState } from 'react';
export const enum DRAWER_TOGGLE_VARIANTS {
OPEN = 'open',
CLOSE = 'close',
}
interface Props {
onToggle: React.MouseEventHandler<HTMLButtonElement>;
variant: DRAWER_TOGGLE_VARIANTS.OPEN | DRAWER_TOGGLE_VARIANTS.CLOSE;
className?: string;
}
export const DrawerToggle = ({
onToggle,
variant = DRAWER_TOGGLE_VARIANTS.CLOSE,
className = '',
}: Props) => {
const [iconName, setIconName] = useState(IconNames.MENU);
const classes = classNames('md:hidden', className);
useEffect(() => {
if (variant === DRAWER_TOGGLE_VARIANTS.OPEN) {
setIconName(IconNames.MENU);
} else {
setIconName(IconNames.CROSS);
}
}, [variant]);
const ariaLabel = `${
variant === DRAWER_TOGGLE_VARIANTS.OPEN ? 'Open' : 'Close'
} Sidebar Navigation Menu`;
return (
<Button
aria-label={ariaLabel}
variant="inline-link"
className={classes}
onClick={onToggle}
>
<Icon name={iconName as IconName} />
</Button>
);
};
@@ -0,0 +1,13 @@
import * as React from 'react';
import classNames from 'classnames';
import type { ReactElement } from 'react';
interface Props {
children: ReactElement | ReactElement[];
className?: string;
}
export const DrawerWrapper = ({ children, className = '' }: Props) => {
const classes = classNames('flex dark:bg-lite-black md:flex-row', className);
return <div className={classes}>{children}</div>;
};
@@ -0,0 +1,63 @@
import * as React from 'react';
import classNames from 'classnames';
import type { ReactElement } from 'react';
interface Props {
children?: ReactElement | ReactElement[];
isMenuOpen?: boolean;
onToggle(): void;
rtl?: boolean;
outerClasses?: string;
innerClasses?: string;
}
export const NavigationDrawer = ({
isMenuOpen = false,
onToggle,
children,
rtl,
outerClasses = '',
innerClasses = '',
}: Props) => {
const width = 'w-full md:w-auto md:min-w-[15%] shrink-0';
const position = 'absolute inset-0 h-full z-10 md:static';
const background = 'bg-black/50 dark:bg-white/50';
const flex = 'flex justify-end overflow-hidden';
const joinedClasses = [flex, width, position, background].join(' ');
const outerStyles = classNames(joinedClasses, {
visible: isMenuOpen,
'invisible md:visible': !isMenuOpen,
'flex-row-reverse': !rtl,
[outerClasses]: outerClasses,
});
const translateClose = rtl ? 'translate-x-full' : '-translate-x-full';
const innerStyles = classNames(
'w-3/4 md:w-full bg-white dark:bg-lite-black',
{
'translate-x-0 transition-transform md:transform-none': isMenuOpen,
[`${translateClose} md:transform-none`]: !isMenuOpen,
[innerClasses]: innerClasses,
}
);
return (
<aside aria-label="Sidebar Navigation Menu" className={outerStyles}>
<div
role="presentation"
aria-label="Content Overlay - Click To Close Sidebar Navigation"
className="md:hidden grow h-full"
onClick={onToggle}
/>
<div
role="group"
aria-label="Sidebar Navigation Grouped Content"
className={innerStyles}
>
{children}
</div>
</aside>
);
};
@@ -0,0 +1,4 @@
export * from './drawer';
export * from './drawer-toggle';
export * from './drawer-content';
export * from './drawer-wrapper';
@@ -0,0 +1,48 @@
import React from 'react';
const Comet = () => {
return (
<svg
viewBox="0 0 118 82"
fill="currentColor"
className="max-w-[7.5rem] mx-auto"
>
<g className="fill-black dark:fill-white">
<path d="M44.3791 67.5864H41.5859V70.3796H44.3791V67.5864Z"></path>
<path d="M47.173 64.7932V62H44.3799V64.7932V67.5863H47.173V64.7932Z"></path>
<path d="M41.5863 70.3794H36V73.1726H41.5863V70.3794Z"></path>
<path d="M44.3791 73.1719H41.5859V75.965H44.3791V73.1719Z"></path>
<path d="M47.173 75.9658H44.3799V81.5521H47.173V75.9658Z"></path>
<path d="M49.966 73.1719H47.1729V75.965H49.966V73.1719Z"></path>
<path d="M55.5521 70.3794H49.9658V73.1726H55.5521V70.3794Z"></path>
<path d="M49.966 67.5864H47.1729V70.3796H49.966V67.5864Z"></path>
<path d="M57.1876 60.564H54V63.7515H57.1876V60.564Z"></path>
<path d="M60.3751 57.3765H57.1875V60.564H60.3751V57.3765Z"></path>
<path d="M63.5626 54.1885H60.375V57.3761H63.5626V54.1885Z"></path>
<path d="M66.7501 51.001H63.5625V54.1886H66.7501V51.001Z"></path>
<path d="M69.9376 47.8135H66.75V51.0011H69.9376V47.8135Z"></path>
<path d="M73.1251 44.626H69.9375V47.8136H73.1251V44.626Z"></path>
<path d="M76.3126 41.4385H73.125V44.6261H76.3126V41.4385Z"></path>
<path d="M79.5001 38.251H76.3125V41.4386H79.5001V38.251Z"></path>
<path d="M82.6886 35.0635H79.501V38.2511H82.6886V35.0635Z"></path>
<path d="M85.8761 31.876H82.6885V35.0636H85.8761V31.876Z"></path>
<path d="M89.0636 28.688H85.876V31.8756H89.0636V28.688Z"></path>
<path d="M92.2511 25.5005H89.0635V28.6881H92.2511V25.5005Z"></path>
<path d="M95.4386 22.313H92.251V25.5006H95.4386V22.313Z"></path>
<path d="M98.6261 19.1255H95.4385V22.3131H98.6261V19.1255Z"></path>
<path d="M101.814 15.938H98.626V19.1256H101.814V15.938Z"></path>
<path d="M105.001 12.7505H101.813V15.9381H105.001V12.7505Z"></path>
<path d="M108.189 9.5625H105.001V12.7501H108.189V9.5625Z"></path>
<path d="M111.376 6.375H108.188V9.56258H111.376V6.375Z"></path>
<path d="M114.565 3.1875H111.377V6.37508H114.565V3.1875Z"></path>
<path d="M117.752 0H114.564V3.18758H117.752V0Z"></path>
<path d="M2.79316 20.793H0V23.5861H2.79316V20.793Z"></path>
<path d="M5.58612 18H2.79297V20.7932H5.58612V18Z"></path>
<path d="M5.58612 23.5859H2.79297V26.3791H5.58612V23.5859Z"></path>
<path d="M8.37909 20.793H5.58594V23.5861H8.37909V20.793Z"></path>
</g>
</svg>
);
};
export default Comet;
@@ -0,0 +1,33 @@
import React, { useContext } from 'react';
import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit';
import Logo from './logo';
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
import LocalContext from '../../context/local-context';
const Header = () => {
const {
vegaWalletDialog: { setConnect, setManage },
toggleTheme,
} = useContext(LocalContext);
return (
<div
className="flex items-stretch pr-16 py-16 bg-black text-white-60"
data-testid="header"
>
<Logo />
<div className="flex items-center gap-4 ml-auto mr-8 relative z-10">
<VegaWalletConnectButton
setConnectDialog={setConnect}
setManageDialog={setManage}
/>
<ThemeSwitcher
onToggle={toggleTheme}
className="-my-4"
sunClassName="text-white"
/>
</div>
</div>
);
};
export default Header;
@@ -0,0 +1 @@
export { default } from './header';
@@ -0,0 +1,18 @@
import React from 'react';
import { NavLink } from 'react-router-dom';
import { t } from '@vegaprotocol/react-helpers';
import { VLogo } from '@vegaprotocol/ui-toolkit';
const Logo = () => {
return (
<NavLink
className="mx-20 text-white"
aria-label={t('Go to home page')}
to="/"
>
<VLogo />
</NavLink>
);
};
export default Logo;
@@ -0,0 +1,33 @@
import React from 'react';
import classNames from 'classnames';
interface Props {
width: number;
height: number;
className: string;
}
const Video = ({ width = 60, height = 60, className = '' }: Partial<Props>) => {
return (
<video
width={width}
height={height}
autoPlay
muted
loop
playsInline
className={classNames(
'absolute left-0 top-0 w-full h-full object-cover',
className
)}
poster="https://vega.xyz/static/poster-image.jpg"
>
<source
src="https://d33wubrfki0l68.cloudfront.net/2500bc5ef1b96927e0220eeb2bef0b22b87bcda1/3e0d3/static/moshed-aa65f0933af9abe9afb5e5663c9b3f68.mp4"
type="video/mp4"
/>
</video>
);
};
export default Video;
@@ -0,0 +1,51 @@
import type { ReactElement } from 'react';
import { LiquidityIconPath } from './liquidity-icon';
import { MarketIconPath } from './market-icon';
import { TradeIconPath } from './trade-icon';
import { PortfolioIconPath } from './portfolio-icon';
interface IconProps {
name: string;
className: string;
}
interface IconSVGWrapperProps {
className: string;
children: ReactElement | ReactElement[] | null;
}
const getIconPath = (name: string): ReactElement | null => {
switch (name) {
case 'liquidity':
return <LiquidityIconPath />;
case 'market':
return <MarketIconPath />;
case 'trade':
return <TradeIconPath />;
case 'portfolio':
return <PortfolioIconPath />;
default:
return null;
}
};
const IconSVGWrapper = ({ className, children }: IconSVGWrapperProps) => {
return (
<svg
role="presentation"
className={className}
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
{children}
</svg>
);
};
export const Icon = ({ name, className }: IconProps) => {
return (
<IconSVGWrapper className={className}>{getIconPath(name)}</IconSVGWrapper>
);
};
@@ -0,0 +1 @@
export * from './icon';
@@ -0,0 +1,15 @@
export const LiquidityIconPath = () => (
<>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12.5268 1.46612L12 1.99999L11.4732 1.46612L12 0.946381L12.5268 1.46612ZM12 3.07542C11.8274 3.25709 11.6185 3.48044 11.3826 3.73943C10.6899 4.49987 9.76793 5.56335 8.84782 6.77789C7.92587 7.99485 7.01715 9.34862 6.34179 10.6903C5.66046 12.0439 5.25 13.3205 5.25 14.4C5.25 19.0485 8.47431 22.15 12 22.15C15.5257 22.15 18.75 19.0485 18.75 14.4C18.75 13.3205 18.3395 12.0439 17.6582 10.6903C16.9829 9.34862 16.0741 7.99485 15.1522 6.77789C14.2321 5.56335 13.3101 4.49987 12.6174 3.73943C12.3815 3.48044 12.1726 3.25709 12 3.07542ZM11.4732 1.46612C11.4734 1.46597 11.4732 1.46612 12 1.99999C12.5268 1.46612 12.5266 1.46597 12.5268 1.46612L12.5336 1.47291L12.5512 1.49036C12.5663 1.5055 12.5884 1.52759 12.6169 1.55634C12.6739 1.61384 12.7566 1.698 12.8615 1.80641C13.071 2.02319 13.3692 2.33722 13.7263 2.72931C14.4399 3.51261 15.3929 4.61164 16.3478 5.8721C17.3009 7.13013 18.2671 8.56386 18.998 10.0159C19.723 11.4561 20.25 12.9795 20.25 14.4C20.25 19.7514 16.4743 23.65 12 23.65C7.52569 23.65 3.75 19.7514 3.75 14.4C3.75 12.9795 4.27704 11.4561 5.00196 10.0159C5.73285 8.56386 6.69913 7.13013 7.65218 5.8721C8.60707 4.61164 9.56014 3.51261 10.2737 2.72931C10.6308 2.33722 10.929 2.02319 11.1385 1.80641C11.2434 1.698 11.3261 1.61384 11.3831 1.55634C11.4116 1.52759 11.4337 1.5055 11.4488 1.49036L11.4664 1.47291L11.4712 1.46817L11.4732 1.46612Z"
/>
<rect x="11.5" y="17.4" width="1" height="1" />
<rect x="12.5" y="16.4" width="1" height="1" />
<rect x="10.5" y="16.4" width="1" height="1" />
<rect x="14.5" y="15.4" width="1" height="1" />
<rect x="13.5" y="11.4" width="1" height="4" />
<rect x="9.5" y="11.4" width="1" height="5" />
</>
);
@@ -0,0 +1,17 @@
export const MarketIconPath = () => (
<>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.5 2H2V20.5V22H3.5H22V20.5H3.5V2Z"
/>
<rect x="5" y="15" width="2" height="2" />
<rect x="7" y="13" width="2" height="2" />
<rect x="9" y="11" width="2" height="2" />
<rect x="11" y="9" width="2" height="2" />
<rect x="13" y="11" width="2" height="2" />
<rect x="15" y="9" width="2" height="2" />
<rect x="17" y="7" width="2" height="2" />
<rect x="19" y="5" width="2" height="2" />
</>
);
@@ -0,0 +1,17 @@
export const PortfolioIconPath = () => (
<>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.5 3.5H15.5V6H8.5V3.5ZM7 6V3.5C7 2.67157 7.67157 2 8.5 2H15.5C16.3284 2 17 2.67157 17 3.5V6H20.5C21.3284 6 22 6.67157 22 7.5V20.5C22 21.3284 21.3284 22 20.5 22H3.5C2.67157 22 2 21.3284 2 20.5V7.5C2 6.67157 2.67157 6 3.5 6H7ZM15.5 7.5H8.5H3.5L3.5 20.5H20.5V7.5H15.5Z"
/>
<rect x="4" y="8" width="2" height="2" />
<rect x="6" y="10" width="2" height="2" />
<rect x="18" y="8" width="2" height="2" />
<rect x="16" y="10" width="2" height="2" />
<rect x="14" y="12" width="2" height="2" />
<rect x="8" y="12" width="2" height="2" />
<rect x="10" y="14" width="2" height="2" />
<rect x="12" y="14" width="2" height="2" />
</>
);

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