Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4441dfe081 | ||
|
|
220da79839 | ||
|
|
3e839fc620 | ||
|
|
baf150fcf5 | ||
|
|
8d08b6a615 | ||
|
|
1e222aba2d | ||
|
|
61c5a7ba68 |
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
name: Feature Epic
|
||||||
|
about: A template to capture and scope user requirements, high level process, and basic mockups for an upcoming feature as part of the initial core spec review process.
|
||||||
|
title: 'FEATURE EPIC: '
|
||||||
|
labels: feature-epic
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Feature
|
||||||
|
|
||||||
|
<Name>
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
- [ ] Define high level requirements
|
||||||
|
- [ ] Create basic mockups
|
||||||
|
- [ ] Update "API Requirements" in core spec
|
||||||
|
- [ ] Update "User-Interface Spec" in relevant front end repo
|
||||||
|
- [ ] Create detailed user stories using normal template
|
||||||
|
|
||||||
|
## High Level Requirements
|
||||||
|
|
||||||
|
## Basic Mockups
|
||||||
|
|
||||||
|
## Link to API Requirements in Core spec
|
||||||
|
|
||||||
|
## Link to User Interface Specs
|
||||||
|
|
||||||
|
## Linked User Stories
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Related issues 🔗
|
# Related issues 🔗
|
||||||
|
|
||||||
Closes #[Issue number here]
|
Issue: #[Issue number here]
|
||||||
|
|
||||||
# Description ℹ️
|
# Description ℹ️
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
after-release:
|
after-release:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
timeout-minutes: 30
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -30,18 +30,20 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Wait for publish to complete
|
||||||
|
uses: lewagon/wait-on-check-action@v1.3.1
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.release.tag_name }}
|
||||||
|
check-name: '(CD) publish dist / trading'
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
wait-interval: 10
|
||||||
|
|
||||||
- name: resolve ipfs hashes for release
|
- name: resolve ipfs hashes for release
|
||||||
run: |
|
run: |
|
||||||
echo "Name: ${{ github.event.release.name }}"
|
echo "Name: ${{ github.event.release.name }}"
|
||||||
echo "Description: ${{ github.event.release.body }}"
|
echo "Description: ${{ github.event.release.body }}"
|
||||||
echo "Tag: ${{ github.event.release.tag_name }}"
|
echo "Tag: ${{ github.event.release.tag_name }}"
|
||||||
commit="$(git rev-list -n 1 ${{ github.event.release.tag_name }})"
|
docker run --rm vegaprotocol/trading:mainnet cat /ipfs-hash > ipfs-hash
|
||||||
echo "Commit: $commit"
|
|
||||||
until docker pull vegaprotocol/trading:$commit; do
|
|
||||||
echo "Image not pushed yet, waiting 60 seconds"
|
|
||||||
sleep 60
|
|
||||||
done
|
|
||||||
docker run --rm vegaprotocol/trading:$commit cat /ipfs-hash > ipfs-hash
|
|
||||||
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
|
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
|
||||||
tar -xzf kubo.tgz
|
tar -xzf kubo.tgz
|
||||||
export PATH="$PATH:$PWD/kubo"
|
export PATH="$PATH:$PWD/kubo"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ name: 'Add Issues To Project Board'
|
|||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GH_NEW_CARD_TO_PROJECT }}
|
GH_TOKEN: ${{ secrets.PROJECT_MANAGE_ACTION }}
|
||||||
PROJECT_ID: ${{ secrets.FRONT_END_PROJECT_ID }}
|
PROJECT_ID: ${{ secrets.FRONT_END_PROJECT_ID }}
|
||||||
ISSUE_ID: ${{ github.event.issue.node_id }}
|
ISSUE_ID: ${{ github.event.issue.node_id }}
|
||||||
USER: ${{ github.actor }}
|
USER: ${{ github.actor }}
|
||||||
|
|||||||
@@ -5,10 +5,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- release/*
|
- release/*
|
||||||
- develop
|
- develop
|
||||||
- main
|
pull_request:
|
||||||
# uncomment pull_request and comment pull_request_target to test CI changes against feature branch not target branch (develop)
|
|
||||||
# pull_request:
|
|
||||||
pull_request_target:
|
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
- ready_for_review
|
- ready_for_review
|
||||||
@@ -49,7 +46,7 @@ jobs:
|
|||||||
|
|
||||||
lint-pr-title:
|
lint-pr-title:
|
||||||
needs: node-modules
|
needs: node-modules
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
name: Verify PR title
|
name: Verify PR title
|
||||||
uses: ./.github/workflows/lint-pr.yml
|
uses: ./.github/workflows/lint-pr.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
@@ -84,6 +81,22 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
main-branch-name: develop
|
main-branch-name: develop
|
||||||
|
|
||||||
|
# See affected apps
|
||||||
|
- name: See affected apps
|
||||||
|
run: |
|
||||||
|
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
|
||||||
|
python3 tools/ci/check-affected.py --github-ref="${{ github.ref }}" --branch-slug="$branch_slug" --event-name="${{ github.event_name }}"
|
||||||
|
|
||||||
|
- name: Verify script result
|
||||||
|
run: |
|
||||||
|
echo "Check outputs from script"
|
||||||
|
echo "projects: ${{ env.PROJECTS }}"
|
||||||
|
echo "projects-e2e: ${{ env.PROJECTS_E2E }}"
|
||||||
|
echo "preview_governance: ${{ env.PREVIEW_GOVERNANCE }}"
|
||||||
|
echo "preview_trading: ${{ env.PREVIEW_TRADING }}"
|
||||||
|
echo "preview_explorer: ${{ env.PREVIEW_EXPLORER }}"
|
||||||
|
echo "preview_tools: ${{ env.PREVIEW_TOOLS }}"
|
||||||
|
|
||||||
- name: Check formatting
|
- name: Check formatting
|
||||||
run: yarn nx format:check
|
run: yarn nx format:check
|
||||||
|
|
||||||
@@ -99,100 +112,6 @@ jobs:
|
|||||||
- name: Build affected
|
- name: Build affected
|
||||||
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
||||||
|
|
||||||
# See affected apps
|
|
||||||
- name: See affected apps
|
|
||||||
run: |
|
|
||||||
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)"
|
|
||||||
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
|
|
||||||
|
|
||||||
echo ">>>> debug"
|
|
||||||
echo "NX_BASE: ${{ env.NX_BASE }}"
|
|
||||||
echo "NX_HEAD: ${{ env.NX_HEAD }}"
|
|
||||||
echo "Affected: ${affected}"
|
|
||||||
echo "Branch slug: ${branch_slug}"
|
|
||||||
echo ">>>> eof debug"
|
|
||||||
|
|
||||||
projects_array=()
|
|
||||||
|
|
||||||
preview_governance="not deployed"
|
|
||||||
preview_trading="not deployed"
|
|
||||||
preview_explorer="not deployed"
|
|
||||||
preview_tools="not deployed"
|
|
||||||
|
|
||||||
# parse if affected is any of three main applications, if none - use all of them
|
|
||||||
if echo "$affected" | grep -q governance; then
|
|
||||||
echo "Governance is affected"
|
|
||||||
projects_array+=("governance")
|
|
||||||
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
|
||||||
fi
|
|
||||||
if echo "$affected" | grep -q trading; then
|
|
||||||
echo "Trading is affected"
|
|
||||||
projects_array+=("trading")
|
|
||||||
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
|
||||||
fi
|
|
||||||
if echo "$affected" | grep -q explorer; then
|
|
||||||
echo "Explorer is affected"
|
|
||||||
projects_array+=("explorer")
|
|
||||||
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
|
||||||
fi
|
|
||||||
if [[ ${#projects_array[@]} -eq 0 ]]; then
|
|
||||||
projects_array=("governance" "trading" "explorer")
|
|
||||||
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
|
||||||
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
|
||||||
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
|
||||||
fi
|
|
||||||
|
|
||||||
# applications parsed before this loop are applicable for running e2e-tests
|
|
||||||
projects_e2e_array=()
|
|
||||||
for project in "${projects_array[@]}"; do
|
|
||||||
projects_e2e_array+=("${project}-e2e")
|
|
||||||
done
|
|
||||||
# all applications below this loop are not applicable for running e2e-test
|
|
||||||
|
|
||||||
# check if pull request event to deploy tools
|
|
||||||
if [[ "${{ github.event_name }}" = "pull_request" ]]; then
|
|
||||||
if echo "$affected" | grep -q multisig-signer; then
|
|
||||||
echo "Tools are affected"
|
|
||||||
echo "Deploying tools on preview"
|
|
||||||
preview_tools=$(printf "https://%s.%s.vega.rocks" "tools" "$branch_slug")
|
|
||||||
|
|
||||||
projects_array+=("multisig-signer")
|
|
||||||
fi
|
|
||||||
# those apps deploy only from develop to mainnet
|
|
||||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
|
||||||
if echo "$affected" | grep -q multisig-signer; then
|
|
||||||
echo "Tools are affected"
|
|
||||||
echo "Deploying tools on s3"
|
|
||||||
|
|
||||||
projects_array+=("multisig-signer")
|
|
||||||
fi
|
|
||||||
if echo "$affected" | grep -q static; then
|
|
||||||
echo "static is affected"
|
|
||||||
echo "Deploying static on s3"
|
|
||||||
|
|
||||||
projects_array+=("static")
|
|
||||||
fi
|
|
||||||
if echo "$affected" | grep -q ui-toolkit; then
|
|
||||||
echo "ui-toolkit is affected"
|
|
||||||
echo "Deploying ui-toolkit on s3"
|
|
||||||
|
|
||||||
projects_array+=("ui-toolkit")
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Projects: ${projects_array[@]}"
|
|
||||||
echo "Projects E2E: ${projects_e2e_array[@]}"
|
|
||||||
projects_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_array[@]}")
|
|
||||||
projects_e2e_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_e2e_array[@]}")
|
|
||||||
|
|
||||||
echo PROJECTS_E2E=$projects_e2e_json >> $GITHUB_ENV
|
|
||||||
echo PROJECTS=$projects_json >> $GITHUB_ENV
|
|
||||||
|
|
||||||
echo PREVIEW_GOVERNANCE=$preview_governance >> $GITHUB_ENV
|
|
||||||
echo PREVIEW_TRADING=$preview_trading >> $GITHUB_ENV
|
|
||||||
echo PREVIEW_EXPLORER=$preview_explorer >> $GITHUB_ENV
|
|
||||||
echo PREVIEW_TOOLS=$preview_tools >> $GITHUB_ENV
|
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
projects: ${{ env.PROJECTS }}
|
projects: ${{ env.PROJECTS }}
|
||||||
projects-e2e: ${{ env.PROJECTS_E2E }}
|
projects-e2e: ${{ env.PROJECTS_E2E }}
|
||||||
@@ -201,6 +120,15 @@ jobs:
|
|||||||
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
||||||
preview_tools: ${{ env.PREVIEW_TOOLS }}
|
preview_tools: ${{ env.PREVIEW_TOOLS }}
|
||||||
|
|
||||||
|
console-e2e:
|
||||||
|
needs: lint-test-build
|
||||||
|
name: '(CI) console python'
|
||||||
|
uses: ./.github/workflows/console-test-run.yml
|
||||||
|
secrets: inherit
|
||||||
|
if: ${{ contains(fromJSON(needs.lint-test-build.outputs.projects), 'trading') && github.event_name == 'pull_request' }}
|
||||||
|
with:
|
||||||
|
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
cypress:
|
cypress:
|
||||||
needs: lint-test-build
|
needs: lint-test-build
|
||||||
name: '(CI) cypress'
|
name: '(CI) cypress'
|
||||||
@@ -209,12 +137,12 @@ jobs:
|
|||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
|
projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
|
||||||
tags: '@smoke @regression'
|
tags: '@smoke'
|
||||||
|
|
||||||
publish-dist:
|
publish-dist:
|
||||||
needs: lint-test-build
|
needs: lint-test-build
|
||||||
name: '(CD) publish dist'
|
name: '(CD) publish dist'
|
||||||
# if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
|
if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo') || github.event_name == 'push' }}
|
||||||
uses: ./.github/workflows/publish-dist.yml
|
uses: ./.github/workflows/publish-dist.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
@@ -225,7 +153,7 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- publish-dist
|
- publish-dist
|
||||||
- lint-test-build
|
- lint-test-build
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }}
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
name: '(CD) comment preview links'
|
name: '(CD) comment preview links'
|
||||||
steps:
|
steps:
|
||||||
@@ -271,7 +199,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
issue-number: ${{ github.event.pull_request.number }}
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
body: |
|
body: |
|
||||||
Previews:
|
Previews
|
||||||
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
|
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
|
||||||
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
|
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
|
||||||
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
|
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
name: (CI) Console tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
github-sha:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run-tests:
|
||||||
|
name: run-tests
|
||||||
|
runs-on: 8-cores
|
||||||
|
timeout-minutes: 20
|
||||||
|
steps:
|
||||||
|
#----------------------------------------------
|
||||||
|
# check-out frontend-monorepo
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Checkout console test repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.github-sha }}
|
||||||
|
#----------------------------------------------
|
||||||
|
# cache node modules
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Cache node modules
|
||||||
|
id: cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: node_modules
|
||||||
|
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
||||||
|
# comment out "restore-keys" if you need to rebuild yarn from 0
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-cache-node-modules-
|
||||||
|
#----------------------------------------------
|
||||||
|
# setup node
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Setup node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version-file: '.nvmrc'
|
||||||
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
cache: yarn
|
||||||
|
#----------------------------------------------
|
||||||
|
# install deps if cache missing
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: yarn install
|
||||||
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
|
run: yarn install --pure-lockfile
|
||||||
|
#----------------------------------------------
|
||||||
|
# build trading
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Build affected spec
|
||||||
|
run: |
|
||||||
|
yarn env-cmd -f ./apps/trading/.env.stagnet1 yarn nx export trading
|
||||||
|
#----------------------------------------------
|
||||||
|
# run trading server
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Run trading server
|
||||||
|
run: |
|
||||||
|
docker run -d -p 80:4200 -v $PWD/docker/nginx.conf:/etc/nginx/conf.d/default.conf -v $PWD/dist/apps/trading/exported:/usr/share/nginx/html nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
|
||||||
|
sleep 5
|
||||||
|
docker ps
|
||||||
|
#----------------------------------------------
|
||||||
|
# check if container persists between runs
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Check server
|
||||||
|
run: |
|
||||||
|
docker ps
|
||||||
|
#----------------------------------------------
|
||||||
|
# check-out tests repo
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Checkout console test repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: vegaprotocol/console-test
|
||||||
|
path: './console-test'
|
||||||
|
#----------------------------------------------
|
||||||
|
# set-up python
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Set up python
|
||||||
|
id: setup-python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.10.11'
|
||||||
|
#----------------------------------------------
|
||||||
|
# ----- install & configure poetry -----
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Install Poetry
|
||||||
|
uses: snok/install-poetry@v1
|
||||||
|
with:
|
||||||
|
virtualenvs-create: true
|
||||||
|
virtualenvs-in-project: true
|
||||||
|
virtualenvs-path: console-test/.venv
|
||||||
|
#----------------------------------------------
|
||||||
|
# load cached venv if cache exists
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Load cached venv
|
||||||
|
id: cached-poetry-dependencies
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: console-test/.venv
|
||||||
|
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}
|
||||||
|
#----------------------------------------------
|
||||||
|
# install dependencies if cache does not exist
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Install dependencies
|
||||||
|
working-directory: ./console-test
|
||||||
|
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
|
||||||
|
run: poetry install --no-interaction --no-root
|
||||||
|
#----------------------------------------------
|
||||||
|
# install vega binaries
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Install vega binaries
|
||||||
|
working-directory: ./console-test
|
||||||
|
run: poetry run python -m vega_sim.tools.load_binaries --force
|
||||||
|
#----------------------------------------------
|
||||||
|
# install playwright
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: install playwright
|
||||||
|
run: poetry run playwright install
|
||||||
|
working-directory: ./console-test
|
||||||
|
#----------------------------------------------
|
||||||
|
# run tests
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: ./console-test
|
||||||
|
run: poetry run pytest -v -s --numprocesses auto --dist loadfile --durations=20
|
||||||
|
- name: Check files
|
||||||
|
run: |
|
||||||
|
ls -al .
|
||||||
|
ls -al console-test
|
||||||
|
#----------------------------------------------
|
||||||
|
# upload traces
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Upload Playwright Trace
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: playwright-trace
|
||||||
|
path: ./traces/
|
||||||
|
retention-days: 15
|
||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
project: ${{ fromJSON(inputs.projects) }}
|
project: ${{ fromJSON(inputs.projects) }}
|
||||||
name: ${{ matrix.project }}
|
name: ${{ matrix.project }}
|
||||||
runs-on: self-hosted-runner
|
runs-on: self-hosted-runner
|
||||||
timeout-minutes: 100
|
timeout-minutes: 120
|
||||||
steps:
|
steps:
|
||||||
# Checks if skip cache was requested
|
# Checks if skip cache was requested
|
||||||
- name: Set skip-nx-cache flag
|
- name: Set skip-nx-cache flag
|
||||||
|
|||||||
@@ -22,6 +22,45 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
|
- name: Init variables
|
||||||
|
run: |
|
||||||
|
echo IS_PR=false >> $GITHUB_ENV
|
||||||
|
echo IS_MAINNET_RELEASE=false >> $GITHUB_ENV
|
||||||
|
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
|
||||||
|
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
||||||
|
echo IS_S3_RELEASE=false >> $GITHUB_ENV
|
||||||
|
echo IS_DEV_IMAGE=false >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is dev image
|
||||||
|
if: ${{ contains(github.ref, 'develop') && github.event_name == 'push' && matrix.app == 'trading' }}
|
||||||
|
run: |
|
||||||
|
echo IS_DEV_IMAGE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is PR
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
run: |
|
||||||
|
echo IS_PR=true >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is mainnet release
|
||||||
|
if: ${{ contains(github.ref, 'release/mainnet') && !contains(github.ref, 'mirror') }}
|
||||||
|
run: |
|
||||||
|
echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is testnet release
|
||||||
|
if: ${{ contains(github.ref, 'release/testnet') }}
|
||||||
|
run: |
|
||||||
|
echo IS_TESTNET_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is IPFS Release
|
||||||
|
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( env.IS_MAINNET_RELEASE == 'true' || env.IS_TESTNET_RELEASE == 'true' ) }}
|
||||||
|
run: |
|
||||||
|
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is S3 Release
|
||||||
|
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' }}
|
||||||
|
run: |
|
||||||
|
echo IS_S3_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
id: quemu
|
id: quemu
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v2
|
||||||
@@ -33,7 +72,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
- name: Log in to the Container registry (ghcr)
|
- name: Log in to the Container registry (ghcr)
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ env.IS_PR == 'true' }}
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
@@ -42,9 +81,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Log in to the Container registry (docker hub)
|
- name: Log in to the Container registry (docker hub)
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
|
||||||
with:
|
with:
|
||||||
# registry: registry.hub.docker.com
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
@@ -65,51 +103,13 @@ jobs:
|
|||||||
- name: Define dist variables
|
- name: Define dist variables
|
||||||
if: ${{ github.event_name == 'push' }}
|
if: ${{ github.event_name == 'push' }}
|
||||||
run: |
|
run: |
|
||||||
envName=''
|
python3 tools/ci/define-dist-variables.py --github-ref="${{ github.ref }}" --app="${{ matrix.app }}"
|
||||||
domain="vega.rocks"
|
|
||||||
bucketName=''
|
|
||||||
|
|
||||||
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
|
- name: Verify script result
|
||||||
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
|
if: ${{ github.event_name == 'push' }}
|
||||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
run: |
|
||||||
envName="stagnet1"
|
echo "BUCKET_NAME=${{ env.BUCKET_NAME }}"
|
||||||
if [[ "${{ matrix.app }}" = "multisig-signer" ]]; then
|
echo "ENV_NAME=${{ env.ENV_NAME }}"
|
||||||
envName="mainnet"
|
|
||||||
bucketName="tools.vega.xyz"
|
|
||||||
fi
|
|
||||||
if [[ "${{ matrix.app }}" = "static" ]]; then
|
|
||||||
envName="mainnet"
|
|
||||||
bucketName="static.vega.xyz"
|
|
||||||
fi
|
|
||||||
if [[ "${{ matrix.app }}" = "ui-toolkit" ]]; then
|
|
||||||
envName="mainnet"
|
|
||||||
bucketName="ui.vega.rocks"
|
|
||||||
fi
|
|
||||||
elif [[ "${{ github.ref }}" =~ .*main$ ]]; then
|
|
||||||
envName="mainnet"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${envName}" = "mainnet" ]]; then
|
|
||||||
domain="vega.xyz"
|
|
||||||
if [[ -z "${bucketName}" ]]; then
|
|
||||||
bucketName="${{ matrix.app }}.${domain}"
|
|
||||||
fi
|
|
||||||
elif [[ "${envName}" = "testnet" ]]; then
|
|
||||||
domain="fairground.wtf"
|
|
||||||
if [[ -z "${bucketName}" ]]; then
|
|
||||||
bucketName="${{ matrix.app }}.${domain}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "${bucketName}" ]]; then
|
|
||||||
bucketName="${{ matrix.app }}.${envName}.${domain}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "bucket name: ${bucketName}"
|
|
||||||
echo "env name: ${envName}"
|
|
||||||
|
|
||||||
echo BUCKET_NAME=${bucketName} >> $GITHUB_ENV
|
|
||||||
echo ENV_NAME=${envName} >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Build local dist
|
- name: Build local dist
|
||||||
run: |
|
run: |
|
||||||
@@ -124,8 +124,12 @@ jobs:
|
|||||||
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
||||||
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
||||||
DIST_LOCATION=dist/storybook/ui-toolkit
|
DIST_LOCATION=dist/storybook/ui-toolkit
|
||||||
|
elif [ "${{ matrix.app }}" = "static" ]; then
|
||||||
|
yarn nx build static || (yarn install && yarn nx build static)
|
||||||
else
|
else
|
||||||
$envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }})
|
$envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }})
|
||||||
|
fi
|
||||||
|
if [[ -z "$DIST_LOCATION" ]]; then
|
||||||
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
||||||
fi
|
fi
|
||||||
mv $DIST_LOCATION dist-result
|
mv $DIST_LOCATION dist-result
|
||||||
@@ -145,7 +149,7 @@ jobs:
|
|||||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||||
|
|
||||||
- name: Image digest
|
- name: Image digest
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ env.IS_PR == 'true' }}
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
|
|
||||||
- name: Sanity check docker image
|
- name: Sanity check docker image
|
||||||
@@ -160,7 +164,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
id: ghcr-push
|
id: ghcr-push
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ env.IS_PR == 'true' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/node-outside-docker.Dockerfile
|
file: docker/node-outside-docker.Dockerfile
|
||||||
@@ -175,7 +179,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
id: dockerhub-push
|
id: dockerhub-push
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/node-outside-docker.Dockerfile
|
file: docker/node-outside-docker.Dockerfile
|
||||||
@@ -185,7 +189,7 @@ jobs:
|
|||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
|
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || '' }}
|
||||||
|
|
||||||
- name: Publish dist as docker image (ghcr - retry)
|
- name: Publish dist as docker image (ghcr - retry)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
@@ -212,13 +216,13 @@ jobs:
|
|||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
|
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
||||||
|
|
||||||
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
||||||
- name: Publish dist to s3
|
- name: Publish dist to s3
|
||||||
uses: jakejarvis/s3-sync-action@master
|
uses: jakejarvis/s3-sync-action@master
|
||||||
# s3 releases are not happening for trading on mainnet - it's IPFS
|
# s3 releases are not happening for trading on mainnet - it's IPFS
|
||||||
if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
|
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
||||||
with:
|
with:
|
||||||
args: --acl private --follow-symlinks --delete
|
args: --acl private --follow-symlinks --delete
|
||||||
env:
|
env:
|
||||||
@@ -229,11 +233,11 @@ jobs:
|
|||||||
SOURCE_DIR: 'dist-result'
|
SOURCE_DIR: 'dist-result'
|
||||||
|
|
||||||
- name: Install aws CLI
|
- name: Install aws CLI
|
||||||
if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
|
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
||||||
uses: unfor19/install-aws-cli-action@master
|
uses: unfor19/install-aws-cli-action@master
|
||||||
|
|
||||||
- name: Perform cache invalidation
|
- name: Perform cache invalidation
|
||||||
if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
|
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
||||||
env:
|
env:
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
@@ -246,16 +250,16 @@ jobs:
|
|||||||
|
|
||||||
- name: Add preview label
|
- name: Add preview label
|
||||||
uses: actions-ecosystem/action-add-labels@v1
|
uses: actions-ecosystem/action-add-labels@v1
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ env.IS_PR == 'true' }}
|
||||||
with:
|
with:
|
||||||
labels: ${{ matrix.app }}-preview
|
labels: ${{ matrix.app }}-preview
|
||||||
number: ${{ github.event.number }}
|
number: ${{ github.event.number }}
|
||||||
|
|
||||||
- name: Trigger fleek deployment
|
- name: Trigger fleek deployment
|
||||||
# release to ipfs happens only on mainnet (represented by main branch) for trading
|
# release to ipfs happens only on mainnet (represented by main branch) for trading
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||||
run: |
|
run: |
|
||||||
if echo ${{ github.ref }} | grep -q main; then
|
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
|
||||||
# display info about app
|
# display info about app
|
||||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
@@ -268,7 +272,7 @@ jobs:
|
|||||||
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
||||||
https://api.fleek.co/graphql
|
https://api.fleek.co/graphql
|
||||||
|
|
||||||
elif echo ${{ github.ref }} | grep -q release/testnet; then
|
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
|
||||||
# display info about app
|
# display info about app
|
||||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
@@ -283,7 +287,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Check out ipfs-redirect
|
- name: Check out ipfs-redirect
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: 'vegaprotocol/ipfs-redirect'
|
repository: 'vegaprotocol/ipfs-redirect'
|
||||||
@@ -292,7 +296,7 @@ jobs:
|
|||||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Update interstitial page to point to the new console
|
- name: Update interstitial page to point to the new console
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
@@ -314,11 +318,11 @@ jobs:
|
|||||||
git config --global user.name "vega-ci-bot"
|
git config --global user.name "vega-ci-bot"
|
||||||
|
|
||||||
# update CID files
|
# update CID files
|
||||||
if echo ${{ github.ref }} | grep -q main; then
|
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
|
||||||
echo $new_hash > cidv0-mainnet.txt
|
echo $new_hash > cidv0-mainnet.txt
|
||||||
echo $new_cid > cidv1-mainnet.txt
|
echo $new_cid > cidv1-mainnet.txt
|
||||||
git add cidv0-mainnet.txt cidv1-mainnet.txt
|
git add cidv0-mainnet.txt cidv1-mainnet.txt
|
||||||
elif echo ${{ github.ref }} | grep -q release/testnet; then
|
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
|
||||||
echo $new_hash > cidv0-fairground.txt
|
echo $new_hash > cidv0-fairground.txt
|
||||||
echo $new_cid > cidv1-fairground.txt
|
echo $new_cid > cidv1-fairground.txt
|
||||||
git add cidv0-fairground.txt cidv1-fairground.txt
|
git add cidv0-fairground.txt cidv1-fairground.txt
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ on:
|
|||||||
- types
|
- types
|
||||||
- utils
|
- utils
|
||||||
- i18n
|
- i18n
|
||||||
|
- wallet
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
|
|||||||
@@ -13,12 +13,6 @@ export const VegaWalletDialogs = () => {
|
|||||||
<>
|
<>
|
||||||
<VegaConnectDialog
|
<VegaConnectDialog
|
||||||
connectors={Connectors}
|
connectors={Connectors}
|
||||||
onChangeOpen={(open) =>
|
|
||||||
appDispatch({
|
|
||||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
|
||||||
isOpen: open,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
riskMessage={<RiskMessage />}
|
riskMessage={<RiskMessage />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,18 @@ import {
|
|||||||
RestConnector,
|
RestConnector,
|
||||||
JsonRpcConnector,
|
JsonRpcConnector,
|
||||||
ViewConnector,
|
ViewConnector,
|
||||||
|
InjectedConnector,
|
||||||
} from '@vegaprotocol/wallet';
|
} from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
export const rest = new RestConnector();
|
export const rest = new RestConnector();
|
||||||
export const jsonRpc = new JsonRpcConnector();
|
export const jsonRpc = new JsonRpcConnector();
|
||||||
|
export const injected = new InjectedConnector();
|
||||||
export const view = new ViewConnector(urlParams.get('address'));
|
export const view = new ViewConnector(urlParams.get('address'));
|
||||||
|
|
||||||
export const Connectors = {
|
export const Connectors = {
|
||||||
|
injected,
|
||||||
rest,
|
rest,
|
||||||
jsonRpc,
|
jsonRpc,
|
||||||
view,
|
view,
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import { TxState } from '../../../hooks/transaction-reducer';
|
|||||||
import { useTransaction } from '../../../hooks/use-transaction';
|
import { useTransaction } from '../../../hooks/use-transaction';
|
||||||
import { BigNumber } from '../../../lib/bignumber';
|
import { BigNumber } from '../../../lib/bignumber';
|
||||||
import { AssociateInfo } from './associate-info';
|
import { AssociateInfo } from './associate-info';
|
||||||
import { removeDecimal, toBigNum } from '@vegaprotocol/utils';
|
import { toBigNum } from '@vegaprotocol/utils';
|
||||||
import type { EthereumConfig } from '@vegaprotocol/web3';
|
import type { EthereumConfig } from '@vegaprotocol/web3';
|
||||||
import { useBalances } from '../../../lib/balances/balances-store';
|
import { useBalances } from '../../../lib/balances/balances-store';
|
||||||
|
import { MaxUint256 } from '@ethersproject/constants';
|
||||||
|
|
||||||
export const WalletAssociate = ({
|
export const WalletAssociate = ({
|
||||||
perform,
|
perform,
|
||||||
@@ -42,7 +43,7 @@ export const WalletAssociate = ({
|
|||||||
} = useTransaction(() => {
|
} = useTransaction(() => {
|
||||||
return token.approve(
|
return token.approve(
|
||||||
ethereumConfig.staking_bridge_contract.address,
|
ethereumConfig.staking_bridge_contract.address,
|
||||||
removeDecimal('1000000', decimals).toString()
|
MaxUint256.toString()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,4 +14,4 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
|
|||||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||||
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||||
# TAG name of the current app version - TODO: bump to the latest upon release
|
# TAG name of the current app version - TODO: bump to the latest upon release
|
||||||
NX_APP_VERSION=v0.20.21-core-0.71.6
|
NX_APP_VERSION=v0.20.23-core-0.71.6
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import {
|
|||||||
RestConnector,
|
RestConnector,
|
||||||
JsonRpcConnector,
|
JsonRpcConnector,
|
||||||
ViewConnector,
|
ViewConnector,
|
||||||
|
InjectedConnector,
|
||||||
} from '@vegaprotocol/wallet';
|
} from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
export const rest = new RestConnector();
|
export const rest = new RestConnector();
|
||||||
export const jsonRpc = new JsonRpcConnector();
|
export const jsonRpc = new JsonRpcConnector();
|
||||||
|
export const injected = new InjectedConnector();
|
||||||
|
|
||||||
let view: ViewConnector;
|
let view: ViewConnector;
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
@@ -16,6 +18,7 @@ if (typeof window !== 'undefined') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Connectors = {
|
export const Connectors = {
|
||||||
|
injected,
|
||||||
rest,
|
rest,
|
||||||
jsonRpc,
|
jsonRpc,
|
||||||
view,
|
view,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import type { Position } from './positions-data-providers';
|
|||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import { PositionStatus, PositionStatusMapping } from '@vegaprotocol/types';
|
import { PositionStatus, PositionStatusMapping } from '@vegaprotocol/types';
|
||||||
import type { ICellRendererParams } from 'ag-grid-community';
|
import type { ICellRendererParams } from 'ag-grid-community';
|
||||||
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
jest.mock('./liquidation-price', () => ({
|
jest.mock('./liquidation-price', () => ({
|
||||||
LiquidationPrice: () => (
|
LiquidationPrice: () => (
|
||||||
@@ -19,7 +20,7 @@ const singleRow: Position = {
|
|||||||
assetSymbol: 'BTC',
|
assetSymbol: 'BTC',
|
||||||
averageEntryPrice: '133',
|
averageEntryPrice: '133',
|
||||||
currentLeverage: 1.1,
|
currentLeverage: 1.1,
|
||||||
decimals: 2,
|
decimals: 2, // this is settlementAsset.decimals
|
||||||
quantum: '0.1',
|
quantum: '0.1',
|
||||||
lossSocializationAmount: '0',
|
lossSocializationAmount: '0',
|
||||||
marginAccountBalance: '12345600',
|
marginAccountBalance: '12345600',
|
||||||
@@ -177,12 +178,22 @@ it('displays allocated margin', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('displays realised and unrealised PNL', async () => {
|
it('displays realised and unrealised PNL', async () => {
|
||||||
|
// pnl cells should be rendered with asset dps
|
||||||
|
const expectedRealised = addDecimalsFormatNumber(
|
||||||
|
singleRow.realisedPNL,
|
||||||
|
singleRow.decimals
|
||||||
|
);
|
||||||
|
const expectedUnrealised = addDecimalsFormatNumber(
|
||||||
|
singleRow.unrealisedPNL,
|
||||||
|
singleRow.decimals
|
||||||
|
);
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(<PositionsTable rowData={singleRowData} isReadOnly={false} />);
|
render(<PositionsTable rowData={singleRowData} isReadOnly={false} />);
|
||||||
});
|
});
|
||||||
const cells = screen.getAllByRole('gridcell');
|
const cells = screen.getAllByRole('gridcell');
|
||||||
expect(cells[9].textContent).toEqual('12.3');
|
expect(cells[9].textContent).toEqual(expectedRealised);
|
||||||
expect(cells[10].textContent).toEqual('45.6');
|
expect(cells[10].textContent).toEqual(expectedUnrealised);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays close button', async () => {
|
it('displays close button', async () => {
|
||||||
|
|||||||
@@ -365,20 +365,14 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
|||||||
valueGetter: ({ data }: VegaValueGetterParams<Position>) => {
|
valueGetter: ({ data }: VegaValueGetterParams<Position>) => {
|
||||||
return !data
|
return !data
|
||||||
? undefined
|
? undefined
|
||||||
: toBigNum(
|
: toBigNum(data.realisedPNL, data.decimals).toNumber();
|
||||||
data.realisedPNL,
|
|
||||||
data.marketDecimalPlaces
|
|
||||||
).toNumber();
|
|
||||||
},
|
},
|
||||||
valueFormatter: ({
|
valueFormatter: ({
|
||||||
data,
|
data,
|
||||||
}: VegaValueFormatterParams<Position, 'realisedPNL'>) => {
|
}: VegaValueFormatterParams<Position, 'realisedPNL'>) => {
|
||||||
return !data
|
return !data
|
||||||
? ''
|
? ''
|
||||||
: addDecimalsFormatNumber(
|
: addDecimalsFormatNumber(data.realisedPNL, data.decimals);
|
||||||
data.realisedPNL,
|
|
||||||
data.marketDecimalPlaces
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
headerTooltip: t(
|
headerTooltip: t(
|
||||||
'Profit or loss is realised whenever your position is reduced to zero and the margin is released back to your collateral balance. P&L excludes any fees paid.'
|
'Profit or loss is realised whenever your position is reduced to zero and the margin is released back to your collateral balance. P&L excludes any fees paid.'
|
||||||
@@ -396,20 +390,14 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
|||||||
valueGetter: ({ data }: VegaValueGetterParams<Position>) => {
|
valueGetter: ({ data }: VegaValueGetterParams<Position>) => {
|
||||||
return !data
|
return !data
|
||||||
? undefined
|
? undefined
|
||||||
: toBigNum(
|
: toBigNum(data.unrealisedPNL, data.decimals).toNumber();
|
||||||
data.unrealisedPNL,
|
|
||||||
data.marketDecimalPlaces
|
|
||||||
).toNumber();
|
|
||||||
},
|
},
|
||||||
valueFormatter: ({
|
valueFormatter: ({
|
||||||
data,
|
data,
|
||||||
}: VegaValueFormatterParams<Position, 'unrealisedPNL'>) =>
|
}: VegaValueFormatterParams<Position, 'unrealisedPNL'>) =>
|
||||||
!data
|
!data
|
||||||
? ''
|
? ''
|
||||||
: addDecimalsFormatNumber(
|
: addDecimalsFormatNumber(data.unrealisedPNL, data.decimals),
|
||||||
data.unrealisedPNL,
|
|
||||||
data.marketDecimalPlaces
|
|
||||||
),
|
|
||||||
headerTooltip: t(
|
headerTooltip: t(
|
||||||
'Unrealised profit is the current profit on your open position. Margin is still allocated to your position.'
|
'Unrealised profit is the current profit on your open position. Margin is still allocated to your position.'
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export const IconChevronLeft = ({ size = 16 }: { size: number }) => {
|
||||||
|
return (
|
||||||
|
<svg width={size} height={size} viewBox="0 0 16 16">
|
||||||
|
<path d="M10.38 1.62L11.13 2.38L5.5 8L11.13 13.62L10.38 14.38L4 8L10.38 1.62Z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@ import { IconArrowDown } from './svg-icons/icon-arrow-down';
|
|||||||
import { IconArrowRight } from './svg-icons/icon-arrow-right';
|
import { IconArrowRight } from './svg-icons/icon-arrow-right';
|
||||||
import { IconBreakdown } from './svg-icons/icon-breakdown';
|
import { IconBreakdown } from './svg-icons/icon-breakdown';
|
||||||
import { IconChevronDown } from './svg-icons/icon-chevron-down';
|
import { IconChevronDown } from './svg-icons/icon-chevron-down';
|
||||||
|
import { IconChevronLeft } from './svg-icons/icon-chevron-left';
|
||||||
import { IconChevronUp } from './svg-icons/icon-chevron-up';
|
import { IconChevronUp } from './svg-icons/icon-chevron-up';
|
||||||
import { IconCopy } from './svg-icons/icon-copy';
|
import { IconCopy } from './svg-icons/icon-copy';
|
||||||
import { IconCross } from './svg-icons/icon-cross';
|
import { IconCross } from './svg-icons/icon-cross';
|
||||||
@@ -26,6 +27,7 @@ export enum VegaIconNames {
|
|||||||
ARROW_RIGHT = 'arrow-right',
|
ARROW_RIGHT = 'arrow-right',
|
||||||
BREAKDOWN = 'breakdown',
|
BREAKDOWN = 'breakdown',
|
||||||
CHEVRON_DOWN = 'chevron-down',
|
CHEVRON_DOWN = 'chevron-down',
|
||||||
|
CHEVRON_LEFT = 'chevron-left',
|
||||||
CHEVRON_UP = 'chevron-up',
|
CHEVRON_UP = 'chevron-up',
|
||||||
COPY = 'copy',
|
COPY = 'copy',
|
||||||
CROSS = 'cross',
|
CROSS = 'cross',
|
||||||
@@ -53,6 +55,7 @@ export const VegaIconNameMap: Record<
|
|||||||
'arrow-down': IconArrowDown,
|
'arrow-down': IconArrowDown,
|
||||||
'arrow-right': IconArrowRight,
|
'arrow-right': IconArrowRight,
|
||||||
'chevron-down': IconChevronDown,
|
'chevron-down': IconChevronDown,
|
||||||
|
'chevron-left': IconChevronLeft,
|
||||||
'chevron-up': IconChevronUp,
|
'chevron-up': IconChevronUp,
|
||||||
'open-external': IconOpenExternal,
|
'open-external': IconOpenExternal,
|
||||||
'question-mark': IconQuestionMark,
|
'question-mark': IconQuestionMark,
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { DocsLinks, ExternalLinks } from '@vegaprotocol/environment';
|
import { DocsLinks, ExternalLinks } from '@vegaprotocol/environment';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import classNames from 'classnames';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
|
import type { VegaConnector } from '../connectors';
|
||||||
|
import { RestConnector } from '../connectors';
|
||||||
|
|
||||||
export const ConnectDialogTitle = ({ children }: { children: ReactNode }) => {
|
export const ConnectDialogTitle = ({ children }: { children: ReactNode }) => {
|
||||||
return (
|
return (
|
||||||
@@ -18,11 +21,35 @@ export const ConnectDialogContent = ({ children }: { children: ReactNode }) => {
|
|||||||
return <div>{children}</div>;
|
return <div>{children}</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ConnectDialogFooter = ({ children }: { children?: ReactNode }) => {
|
export const ConnectDialogFooter = ({
|
||||||
|
connector,
|
||||||
|
}: {
|
||||||
|
connector: VegaConnector | undefined;
|
||||||
|
}) => {
|
||||||
|
const wrapperClasses = classNames(
|
||||||
|
'flex justify-center gap-4',
|
||||||
|
'px-4 md:px-8 pt-4 md:pt-6',
|
||||||
|
'border-t border-vega-light-200 dark:border-vega-dark-200',
|
||||||
|
'text-vega-light-400 dark:text-vega-dark-400'
|
||||||
|
);
|
||||||
|
const isHostedWalletSelected = connector instanceof RestConnector;
|
||||||
return (
|
return (
|
||||||
<footer className="flex justify-center gap-4 px-4 md:px-8 pt-4 md:pt-6 -mx-4 md:-mx-8 border-t border-neutral-500 text-neutral-500 dark:text-neutral-400 mt-6">
|
<footer className={wrapperClasses}>
|
||||||
{children ? (
|
{isHostedWalletSelected ? (
|
||||||
children
|
<p className="text-center">
|
||||||
|
{t('For demo purposes get a ')}
|
||||||
|
<Link
|
||||||
|
href={ExternalLinks.VEGA_WALLET_HOSTED_URL}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{t('hosted wallet')}
|
||||||
|
</Link>
|
||||||
|
{t(', or for the real experience create a wallet in the ')}
|
||||||
|
<Link href={ExternalLinks.VEGA_WALLET_URL}>
|
||||||
|
{t('Vega wallet app')}
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Link href={ExternalLinks.VEGA_WALLET_URL}>
|
<Link href={ExternalLinks.VEGA_WALLET_URL}>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
import type { VegaConnectDialogProps } from '..';
|
import type { VegaConnectDialogProps } from '..';
|
||||||
import {
|
import {
|
||||||
ClientErrors,
|
ClientErrors,
|
||||||
|
InjectedConnector,
|
||||||
JsonRpcConnector,
|
JsonRpcConnector,
|
||||||
RestConnector,
|
RestConnector,
|
||||||
ViewConnector,
|
ViewConnector,
|
||||||
@@ -24,6 +25,12 @@ import {
|
|||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import type { ChainIdQuery } from './__generated__/ChainId';
|
import type { ChainIdQuery } from './__generated__/ChainId';
|
||||||
import { ChainIdDocument } from './__generated__/ChainId';
|
import { ChainIdDocument } from './__generated__/ChainId';
|
||||||
|
import {
|
||||||
|
mockBrowserWallet,
|
||||||
|
clearBrowserWallet,
|
||||||
|
delayedReject,
|
||||||
|
delayedResolve,
|
||||||
|
} from '../test-helpers';
|
||||||
|
|
||||||
const mockUpdateDialogOpen = jest.fn();
|
const mockUpdateDialogOpen = jest.fn();
|
||||||
const mockCloseVegaDialog = jest.fn();
|
const mockCloseVegaDialog = jest.fn();
|
||||||
@@ -49,10 +56,12 @@ const INITIAL_KEY = 'some-key';
|
|||||||
const rest = new RestConnector();
|
const rest = new RestConnector();
|
||||||
const jsonRpc = new JsonRpcConnector();
|
const jsonRpc = new JsonRpcConnector();
|
||||||
const view = new ViewConnector(INITIAL_KEY);
|
const view = new ViewConnector(INITIAL_KEY);
|
||||||
|
const injected = new InjectedConnector();
|
||||||
const connectors = {
|
const connectors = {
|
||||||
rest,
|
rest,
|
||||||
jsonRpc,
|
jsonRpc,
|
||||||
view,
|
view,
|
||||||
|
injected,
|
||||||
};
|
};
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
@@ -105,7 +114,7 @@ describe('VegaConnectDialog', () => {
|
|||||||
expect(screen.getByTestId('connector-jsonRpc')).toHaveTextContent(
|
expect(screen.getByTestId('connector-jsonRpc')).toHaveTextContent(
|
||||||
'Connect Vega wallet'
|
'Connect Vega wallet'
|
||||||
);
|
);
|
||||||
expect(screen.getByTestId('connector-hosted')).toHaveTextContent(
|
expect(screen.getByTestId('connector-rest')).toHaveTextContent(
|
||||||
'Hosted Fairground wallet'
|
'Hosted Fairground wallet'
|
||||||
);
|
);
|
||||||
expect(screen.getByTestId('connector-view')).toHaveTextContent(
|
expect(screen.getByTestId('connector-view')).toHaveTextContent(
|
||||||
@@ -113,6 +122,17 @@ describe('VegaConnectDialog', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('displays browser wallet option if detected on window object', async () => {
|
||||||
|
mockBrowserWallet();
|
||||||
|
render(generateJSX());
|
||||||
|
const list = await screen.findByTestId('connectors-list');
|
||||||
|
expect(list.children).toHaveLength(4);
|
||||||
|
expect(screen.getByTestId('connector-injected')).toHaveTextContent(
|
||||||
|
'Connect Web wallet'
|
||||||
|
);
|
||||||
|
clearBrowserWallet();
|
||||||
|
});
|
||||||
|
|
||||||
describe('RestConnector', () => {
|
describe('RestConnector', () => {
|
||||||
it('connects', async () => {
|
it('connects', async () => {
|
||||||
const spy = jest
|
const spy = jest
|
||||||
@@ -229,17 +249,19 @@ describe('VegaConnectDialog', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOnCheckCompat = jest
|
spyOnCheckCompat = jest
|
||||||
.spyOn(connectors.jsonRpc, 'checkCompat')
|
.spyOn(connectors.jsonRpc, 'checkCompat')
|
||||||
.mockImplementation(() => delayedResolve(true));
|
.mockImplementation(() => delayedResolve(true, delay));
|
||||||
spyOnGetChainId = jest
|
spyOnGetChainId = jest
|
||||||
.spyOn(connectors.jsonRpc, 'getChainId')
|
.spyOn(connectors.jsonRpc, 'getChainId')
|
||||||
.mockImplementation(() => delayedResolve({ chainID: mockChainId }));
|
.mockImplementation(() =>
|
||||||
|
delayedResolve({ chainID: mockChainId }, delay)
|
||||||
|
);
|
||||||
spyOnConnectWallet = jest
|
spyOnConnectWallet = jest
|
||||||
.spyOn(connectors.jsonRpc, 'connectWallet')
|
.spyOn(connectors.jsonRpc, 'connectWallet')
|
||||||
.mockImplementation(() => delayedResolve(null));
|
.mockImplementation(() => delayedResolve(null, delay));
|
||||||
spyOnConnect = jest
|
spyOnConnect = jest
|
||||||
.spyOn(connectors.jsonRpc, 'connect')
|
.spyOn(connectors.jsonRpc, 'connect')
|
||||||
.mockImplementation(() =>
|
.mockImplementation(() =>
|
||||||
delayedResolve([{ publicKey: 'pubkey', name: 'test key 1' }])
|
delayedResolve([{ publicKey: 'pubkey', name: 'test key 1' }], delay)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -351,18 +373,6 @@ describe('VegaConnectDialog', () => {
|
|||||||
expect(screen.getByText('An unknown error occurred')).toBeInTheDocument();
|
expect(screen.getByText('An unknown error occurred')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
function delayedResolve<T>(result: T): Promise<T> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
setTimeout(() => resolve(result), delay);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function delayedReject<T>(result: T): Promise<T> {
|
|
||||||
return new Promise((_, reject) => {
|
|
||||||
setTimeout(() => reject(result), delay);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function selectJsonRpc() {
|
async function selectJsonRpc() {
|
||||||
expect(await screen.findByRole('dialog')).toBeInTheDocument();
|
expect(await screen.findByRole('dialog')).toBeInTheDocument();
|
||||||
fireEvent.click(await screen.findByTestId('connector-jsonRpc'));
|
fireEvent.click(await screen.findByTestId('connector-jsonRpc'));
|
||||||
@@ -439,4 +449,109 @@ describe('VegaConnectDialog', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('InjectedConnector', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
jest.useRealTimers();
|
||||||
|
localStorage.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
clearBrowserWallet();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('connects', async () => {
|
||||||
|
const delay = 100;
|
||||||
|
const vegaWindow = {
|
||||||
|
getChainId: jest.fn(() =>
|
||||||
|
delayedResolve({ chainID: mockChainId }, delay)
|
||||||
|
),
|
||||||
|
connectWallet: jest.fn(() => delayedResolve(null, delay)),
|
||||||
|
disconnectWallet: jest.fn(() => delayedResolve(undefined, delay)),
|
||||||
|
listKeys: jest.fn(() =>
|
||||||
|
delayedResolve(
|
||||||
|
{
|
||||||
|
keys: [{ name: 'test key', publicKey: '0x123' }],
|
||||||
|
},
|
||||||
|
100
|
||||||
|
)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
mockBrowserWallet(vegaWindow);
|
||||||
|
render(generateJSX());
|
||||||
|
await selectInjected();
|
||||||
|
|
||||||
|
// Chain check
|
||||||
|
expect(screen.getByText('Verifying chain')).toBeInTheDocument();
|
||||||
|
expect(vegaWindow.getChainId).toHaveBeenCalled();
|
||||||
|
await act(async () => {
|
||||||
|
jest.advanceTimersByTime(delay);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Await user connect
|
||||||
|
expect(screen.getByText('Connecting...')).toBeInTheDocument();
|
||||||
|
expect(vegaWindow.connectWallet).toHaveBeenCalled();
|
||||||
|
await act(async () => {
|
||||||
|
jest.advanceTimersByTime(delay);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Connect (list keys)
|
||||||
|
expect(vegaWindow.listKeys).toHaveBeenCalled();
|
||||||
|
await act(async () => {
|
||||||
|
jest.advanceTimersByTime(delay);
|
||||||
|
});
|
||||||
|
expect(screen.getByText('Successfully connected')).toBeInTheDocument();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.advanceTimersByTime(CLOSE_DELAY);
|
||||||
|
});
|
||||||
|
expect(mockCloseVegaDialog).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles invalid chain', async () => {
|
||||||
|
const delay = 100;
|
||||||
|
const invalidChain = 'invalid chain';
|
||||||
|
const vegaWindow = {
|
||||||
|
getChainId: jest.fn(() =>
|
||||||
|
delayedResolve({ chainID: invalidChain }, delay)
|
||||||
|
),
|
||||||
|
connectWallet: jest.fn(() => delayedResolve(null, delay)),
|
||||||
|
disconnectWallet: jest.fn(() => delayedResolve(undefined, delay)),
|
||||||
|
listKeys: jest.fn(() =>
|
||||||
|
delayedResolve(
|
||||||
|
{
|
||||||
|
keys: [{ name: 'test key', publicKey: '0x123' }],
|
||||||
|
},
|
||||||
|
100
|
||||||
|
)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
mockBrowserWallet(vegaWindow);
|
||||||
|
render(generateJSX());
|
||||||
|
await selectInjected();
|
||||||
|
|
||||||
|
// Chain check
|
||||||
|
expect(screen.getByText('Verifying chain')).toBeInTheDocument();
|
||||||
|
expect(vegaWindow.getChainId).toHaveBeenCalled();
|
||||||
|
await act(async () => {
|
||||||
|
jest.advanceTimersByTime(delay);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('Wrong network')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByText(
|
||||||
|
new RegExp(`set your wallet network in your app to "${mockChainId}"`)
|
||||||
|
)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function selectInjected() {
|
||||||
|
expect(await screen.findByRole('dialog')).toBeInTheDocument();
|
||||||
|
fireEvent.click(await screen.findByTestId('connector-injected'));
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,45 +3,50 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Dialog,
|
Dialog,
|
||||||
FormGroup,
|
FormGroup,
|
||||||
Icon,
|
|
||||||
Input,
|
Input,
|
||||||
Link,
|
VegaIcon,
|
||||||
Loader,
|
VegaIconNames,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import type { WalletClientError } from '@vegaprotocol/wallet-client';
|
import type { WalletClientError } from '@vegaprotocol/wallet-client';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { VegaConnector } from '../connectors';
|
import type { VegaConnector } from '../connectors';
|
||||||
|
import { InjectedConnector } from '../connectors';
|
||||||
import { ViewConnector } from '../connectors';
|
import { ViewConnector } from '../connectors';
|
||||||
import { JsonRpcConnector, RestConnector } from '../connectors';
|
import { JsonRpcConnector, RestConnector } from '../connectors';
|
||||||
import { RestConnectorForm } from './rest-connector-form';
|
import { RestConnectorForm } from './rest-connector-form';
|
||||||
import { JsonRpcConnectorForm } from './json-rpc-connector-form';
|
import { JsonRpcConnectorForm } from './json-rpc-connector-form';
|
||||||
import {
|
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||||
Networks,
|
|
||||||
useEnvironment,
|
|
||||||
ExternalLinks,
|
|
||||||
} from '@vegaprotocol/environment';
|
|
||||||
import {
|
import {
|
||||||
ConnectDialogContent,
|
ConnectDialogContent,
|
||||||
ConnectDialogFooter,
|
ConnectDialogFooter,
|
||||||
ConnectDialogTitle,
|
ConnectDialogTitle,
|
||||||
} from './connect-dialog-elements';
|
} from './connect-dialog-elements';
|
||||||
import type { Status } from '../use-json-rpc-connect';
|
import type { Status as JsonRpcStatus } from '../use-json-rpc-connect';
|
||||||
|
import type { Status as InjectedStatus } from '../use-injected-connector';
|
||||||
import { useJsonRpcConnect } from '../use-json-rpc-connect';
|
import { useJsonRpcConnect } from '../use-json-rpc-connect';
|
||||||
import { ViewConnectorForm } from './view-connector-form';
|
import { ViewConnectorForm } from './view-connector-form';
|
||||||
import { useChainIdQuery } from './__generated__/ChainId';
|
import { useChainIdQuery } from './__generated__/ChainId';
|
||||||
import { useVegaWallet } from '../use-vega-wallet';
|
import { useVegaWallet } from '../use-vega-wallet';
|
||||||
|
import { useInjectedConnector } from '../use-injected-connector';
|
||||||
|
import { InjectedConnectorForm } from './injected-connector-form';
|
||||||
|
|
||||||
export const CLOSE_DELAY = 1700;
|
export const CLOSE_DELAY = 1700;
|
||||||
type Connectors = { [key: string]: VegaConnector };
|
type Connectors = { [key: string]: VegaConnector };
|
||||||
type WalletType = 'jsonRpc' | 'hosted' | 'view';
|
export type WalletType = 'injected' | 'jsonRpc' | 'rest' | 'view';
|
||||||
|
|
||||||
export interface VegaConnectDialogProps {
|
export interface VegaConnectDialogProps {
|
||||||
connectors: Connectors;
|
connectors: Connectors;
|
||||||
onChangeOpen?: (open: boolean) => void;
|
|
||||||
riskMessage?: React.ReactNode;
|
riskMessage?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface VegaWalletDialogStore {
|
||||||
|
vegaWalletDialogOpen: boolean;
|
||||||
|
updateVegaWalletDialog: (open: boolean) => void;
|
||||||
|
openVegaWalletDialog: () => void;
|
||||||
|
closeVegaWalletDialog: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
export const useVegaWalletDialogStore = create<VegaWalletDialogStore>()(
|
export const useVegaWalletDialogStore = create<VegaWalletDialogStore>()(
|
||||||
(set) => ({
|
(set) => ({
|
||||||
vegaWalletDialogOpen: false,
|
vegaWalletDialogOpen: false,
|
||||||
@@ -52,32 +57,20 @@ export const useVegaWalletDialogStore = create<VegaWalletDialogStore>()(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
export interface VegaWalletDialogStore {
|
|
||||||
vegaWalletDialogOpen: boolean;
|
|
||||||
updateVegaWalletDialog: (open: boolean) => void;
|
|
||||||
openVegaWalletDialog: () => void;
|
|
||||||
closeVegaWalletDialog: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const VegaConnectDialog = ({
|
export const VegaConnectDialog = ({
|
||||||
connectors,
|
connectors,
|
||||||
onChangeOpen,
|
|
||||||
riskMessage,
|
riskMessage,
|
||||||
}: VegaConnectDialogProps) => {
|
}: VegaConnectDialogProps) => {
|
||||||
|
const { disconnect, acknowledgeNeeded } = useVegaWallet();
|
||||||
const vegaWalletDialogOpen = useVegaWalletDialogStore(
|
const vegaWalletDialogOpen = useVegaWalletDialogStore(
|
||||||
(store) => store.vegaWalletDialogOpen
|
(store) => store.vegaWalletDialogOpen
|
||||||
);
|
);
|
||||||
const updateVegaWalletDialog = useVegaWalletDialogStore(
|
const updateVegaWalletDialog = useVegaWalletDialogStore(
|
||||||
(store) => (open: boolean) => {
|
(store) => (open: boolean) => {
|
||||||
store.updateVegaWalletDialog(open);
|
store.updateVegaWalletDialog(open);
|
||||||
onChangeOpen?.(open);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const closeVegaWalletDialog = useVegaWalletDialogStore((store) => () => {
|
|
||||||
store.closeVegaWalletDialog();
|
|
||||||
onChangeOpen?.(false);
|
|
||||||
});
|
|
||||||
const { disconnect, acknowledgeNeeded } = useVegaWallet();
|
|
||||||
const onVegaWalletDialogChange = useCallback(
|
const onVegaWalletDialogChange = useCallback(
|
||||||
(open: boolean) => {
|
(open: boolean) => {
|
||||||
updateVegaWalletDialog(open);
|
updateVegaWalletDialog(open);
|
||||||
@@ -88,41 +81,9 @@ export const VegaConnectDialog = ({
|
|||||||
[updateVegaWalletDialog, acknowledgeNeeded, disconnect]
|
[updateVegaWalletDialog, acknowledgeNeeded, disconnect]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data, error, loading } = useChainIdQuery();
|
// Ensure we have a chain Id so we can compare with wallet chain id.
|
||||||
|
// This value will already be in the cache, if it failed the app wont render
|
||||||
const renderContent = () => {
|
const { data } = useChainIdQuery();
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<ConnectDialogContent>
|
|
||||||
<ConnectDialogTitle>
|
|
||||||
{t('Could not retrieve chain id')}
|
|
||||||
</ConnectDialogTitle>
|
|
||||||
<ConnectDialogFooter />
|
|
||||||
</ConnectDialogContent>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loading || !data) {
|
|
||||||
return (
|
|
||||||
<ConnectDialogContent>
|
|
||||||
<ConnectDialogTitle>{t('Fetching chain ID')}</ConnectDialogTitle>
|
|
||||||
<div className="flex justify-center items-center my-6">
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
<ConnectDialogFooter />
|
|
||||||
</ConnectDialogContent>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ConnectDialogContainer
|
|
||||||
connectors={connectors}
|
|
||||||
closeDialog={closeVegaWalletDialog}
|
|
||||||
appChainId={data.statistics.chainId}
|
|
||||||
riskMessage={riskMessage}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
@@ -130,29 +91,35 @@ export const VegaConnectDialog = ({
|
|||||||
size="small"
|
size="small"
|
||||||
onChange={onVegaWalletDialogChange}
|
onChange={onVegaWalletDialogChange}
|
||||||
>
|
>
|
||||||
{renderContent()}
|
{data && (
|
||||||
|
<ConnectDialogContainer
|
||||||
|
connectors={connectors}
|
||||||
|
appChainId={data.statistics.chainId}
|
||||||
|
riskMessage={riskMessage}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ConnectDialogContainer = ({
|
const ConnectDialogContainer = ({
|
||||||
connectors,
|
connectors,
|
||||||
closeDialog,
|
|
||||||
appChainId,
|
appChainId,
|
||||||
riskMessage,
|
riskMessage,
|
||||||
}: {
|
}: {
|
||||||
connectors: Connectors;
|
connectors: Connectors;
|
||||||
closeDialog: () => void;
|
|
||||||
appChainId: string;
|
appChainId: string;
|
||||||
riskMessage?: React.ReactNode;
|
riskMessage?: React.ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
const { VEGA_WALLET_URL, VEGA_ENV, HOSTED_WALLET_URL } = useEnvironment();
|
const { VEGA_WALLET_URL, VEGA_ENV, HOSTED_WALLET_URL } = useEnvironment();
|
||||||
|
const closeDialog = useVegaWalletDialogStore(
|
||||||
|
(store) => store.closeVegaWalletDialog
|
||||||
|
);
|
||||||
const [selectedConnector, setSelectedConnector] = useState<VegaConnector>();
|
const [selectedConnector, setSelectedConnector] = useState<VegaConnector>();
|
||||||
const [walletUrl, setWalletUrl] = useState(VEGA_WALLET_URL || '');
|
const [walletUrl, setWalletUrl] = useState(VEGA_WALLET_URL || '');
|
||||||
const [walletType, setWalletType] = useState<WalletType>();
|
|
||||||
const reset = useCallback(() => {
|
const reset = useCallback(() => {
|
||||||
setSelectedConnector(undefined);
|
setSelectedConnector(undefined);
|
||||||
setWalletType(undefined);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const delayedOnConnect = useCallback(() => {
|
const delayedOnConnect = useCallback(() => {
|
||||||
@@ -161,52 +128,59 @@ const ConnectDialogContainer = ({
|
|||||||
}, CLOSE_DELAY);
|
}, CLOSE_DELAY);
|
||||||
}, [closeDialog]);
|
}, [closeDialog]);
|
||||||
|
|
||||||
const { connect, ...jsonRpcState } = useJsonRpcConnect(delayedOnConnect);
|
const { connect: jsonRpcConnect, ...jsonRpcState } =
|
||||||
|
useJsonRpcConnect(delayedOnConnect);
|
||||||
|
const { connect: injectedConnect, ...injectedState } =
|
||||||
|
useInjectedConnector(delayedOnConnect);
|
||||||
|
|
||||||
const handleSelect = (type: WalletType, isHosted = false) => {
|
const handleSelect = (type: WalletType) => {
|
||||||
let connector;
|
const connector = connectors[type];
|
||||||
|
|
||||||
if (isHosted) {
|
// If type is rest user has selected the hosted wallet option. So here
|
||||||
// If the user has selected hosted wallet ensure that we are connecting to https://vega-hosted-wallet.on.fleek.co/
|
// we ensure that we are connecting to https://vega-hosted-wallet.on.fleek.co/
|
||||||
// otherwise use the default walletUrl or what has been put in the input
|
// otherwise use walletUrl which defaults to the localhost:1789
|
||||||
connector = connectors['rest'];
|
connector.url = type === 'rest' ? HOSTED_WALLET_URL : walletUrl;
|
||||||
connector.url = HOSTED_WALLET_URL || walletUrl;
|
|
||||||
} else {
|
|
||||||
connector = connectors[type];
|
|
||||||
connector.url = walletUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!connector) {
|
if (!connector) {
|
||||||
|
// we should never get here unless connectors are not configured correctly
|
||||||
throw new Error(`Connector type: ${type} not configured`);
|
throw new Error(`Connector type: ${type} not configured`);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedConnector(connector);
|
setSelectedConnector(connector);
|
||||||
setWalletType(type);
|
|
||||||
|
|
||||||
// Immediately connect on selection if jsonRpc is selected, we can't do this
|
// Immediately connect on selection if jsonRpc is selected, we can't do this
|
||||||
// for rest because we need to show an authentication form
|
// for rest because we need to show an authentication form
|
||||||
if (connector instanceof JsonRpcConnector) {
|
if (connector instanceof JsonRpcConnector) {
|
||||||
connect(connector, appChainId);
|
jsonRpcConnect(connector, appChainId);
|
||||||
|
} else if (connector instanceof InjectedConnector) {
|
||||||
|
injectedConnect(connector, appChainId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return selectedConnector !== undefined && walletType !== undefined ? (
|
return (
|
||||||
<SelectedForm
|
<>
|
||||||
type={walletType}
|
<ConnectDialogContent>
|
||||||
connector={selectedConnector}
|
{selectedConnector !== undefined ? (
|
||||||
jsonRpcState={jsonRpcState}
|
<SelectedForm
|
||||||
onConnect={closeDialog}
|
connector={selectedConnector}
|
||||||
appChainId={appChainId}
|
jsonRpcState={jsonRpcState}
|
||||||
reset={reset}
|
injectedState={injectedState}
|
||||||
riskMessage={riskMessage}
|
onConnect={closeDialog}
|
||||||
/>
|
appChainId={appChainId}
|
||||||
) : (
|
reset={reset}
|
||||||
<ConnectorList
|
riskMessage={riskMessage}
|
||||||
walletUrl={walletUrl}
|
/>
|
||||||
setWalletUrl={setWalletUrl}
|
) : (
|
||||||
onSelect={handleSelect}
|
<ConnectorList
|
||||||
isMainnet={VEGA_ENV === Networks.MAINNET}
|
walletUrl={walletUrl}
|
||||||
/>
|
setWalletUrl={setWalletUrl}
|
||||||
|
onSelect={handleSelect}
|
||||||
|
isMainnet={VEGA_ENV === Networks.MAINNET}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ConnectDialogContent>
|
||||||
|
<ConnectDialogFooter connector={selectedConnector} />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -216,136 +190,129 @@ const ConnectorList = ({
|
|||||||
setWalletUrl,
|
setWalletUrl,
|
||||||
isMainnet,
|
isMainnet,
|
||||||
}: {
|
}: {
|
||||||
onSelect: (type: WalletType, isHosted?: boolean) => void;
|
onSelect: (type: WalletType) => void;
|
||||||
walletUrl: string;
|
walletUrl: string;
|
||||||
setWalletUrl: (value: string) => void;
|
setWalletUrl: (value: string) => void;
|
||||||
isMainnet: boolean;
|
isMainnet: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ConnectDialogContent>
|
<ConnectDialogTitle>{t('Connect')}</ConnectDialogTitle>
|
||||||
<ConnectDialogTitle>{t('Connect')}</ConnectDialogTitle>
|
<CustomUrlInput walletUrl={walletUrl} setWalletUrl={setWalletUrl} />
|
||||||
<CustomUrlInput walletUrl={walletUrl} setWalletUrl={setWalletUrl} />
|
<ul data-testid="connectors-list" className="mb-6">
|
||||||
<ul data-testid="connectors-list" className="mb-6">
|
<li className="mb-4 last:mb-0">
|
||||||
|
<ConnectionOption
|
||||||
|
type="jsonRpc"
|
||||||
|
text={t('Connect Vega wallet')}
|
||||||
|
onClick={() => onSelect('jsonRpc')}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
{'vega' in window && (
|
||||||
<li className="mb-4 last:mb-0">
|
<li className="mb-4 last:mb-0">
|
||||||
<ConnectionOption
|
<ConnectionOption
|
||||||
type="jsonRpc"
|
type="injected"
|
||||||
text={t('Connect Vega wallet')}
|
text={t('Connect Web wallet')}
|
||||||
onClick={() => onSelect('jsonRpc')}
|
onClick={() => onSelect('injected')}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
{!isMainnet && (
|
)}
|
||||||
<li className="mb-4 last:mb-0">
|
{!isMainnet && (
|
||||||
<ConnectionOption
|
|
||||||
type="hosted"
|
|
||||||
text={t('Hosted Fairground wallet')}
|
|
||||||
onClick={() => onSelect('hosted', true)}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
)}
|
|
||||||
<li className="mb-4 last:mb-0">
|
<li className="mb-4 last:mb-0">
|
||||||
<div className="my-4 text-center text-vega-dark-400">{t('OR')}</div>
|
|
||||||
<ConnectionOption
|
<ConnectionOption
|
||||||
type="view"
|
type="rest"
|
||||||
text={t('View as vega user')}
|
text={t('Hosted Fairground wallet')}
|
||||||
onClick={() => onSelect('view')}
|
onClick={() => onSelect('rest')}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
)}
|
||||||
</ConnectDialogContent>
|
<li className="mb-4 last:mb-0">
|
||||||
<ConnectDialogFooter />
|
<div className="my-4 text-center">{t('OR')}</div>
|
||||||
|
<ConnectionOption
|
||||||
|
type="view"
|
||||||
|
text={t('View as vega user')}
|
||||||
|
onClick={() => onSelect('view')}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SelectedForm = ({
|
const SelectedForm = ({
|
||||||
type,
|
|
||||||
connector,
|
connector,
|
||||||
appChainId,
|
appChainId,
|
||||||
jsonRpcState,
|
jsonRpcState,
|
||||||
|
injectedState,
|
||||||
reset,
|
reset,
|
||||||
onConnect,
|
onConnect,
|
||||||
riskMessage,
|
riskMessage,
|
||||||
}: {
|
}: {
|
||||||
type: WalletType;
|
|
||||||
connector: VegaConnector;
|
connector: VegaConnector;
|
||||||
appChainId: string;
|
appChainId: string;
|
||||||
jsonRpcState: {
|
jsonRpcState: {
|
||||||
status: Status;
|
status: JsonRpcStatus;
|
||||||
error: WalletClientError | null;
|
error: WalletClientError | null;
|
||||||
};
|
};
|
||||||
|
injectedState: {
|
||||||
|
status: InjectedStatus;
|
||||||
|
error: Error | null;
|
||||||
|
};
|
||||||
reset: () => void;
|
reset: () => void;
|
||||||
onConnect: () => void;
|
onConnect: () => void;
|
||||||
riskMessage?: React.ReactNode;
|
riskMessage?: React.ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
|
if (connector instanceof InjectedConnector) {
|
||||||
|
return (
|
||||||
|
<InjectedConnectorForm
|
||||||
|
status={injectedState.status}
|
||||||
|
error={injectedState.error}
|
||||||
|
onConnect={onConnect}
|
||||||
|
appChainId={appChainId}
|
||||||
|
reset={reset}
|
||||||
|
riskMessage={riskMessage}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (connector instanceof RestConnector) {
|
if (connector instanceof RestConnector) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ConnectDialogContent>
|
<button
|
||||||
<button
|
onClick={reset}
|
||||||
onClick={reset}
|
className="absolute p-2 top-0 left-0 md:top-2 md:left-2"
|
||||||
className="absolute p-2 top-0 left-0 md:top-2 md:left-2"
|
data-testid="back-button"
|
||||||
data-testid="back-button"
|
>
|
||||||
>
|
<VegaIcon name={VegaIconNames.CHEVRON_LEFT} />
|
||||||
<Icon name={'chevron-left'} ariaLabel="back" size={4} />
|
</button>
|
||||||
</button>
|
<ConnectDialogTitle>{t('Connect')}</ConnectDialogTitle>
|
||||||
<ConnectDialogTitle>{t('Connect')}</ConnectDialogTitle>
|
<div className="mb-2">
|
||||||
<div className="mb-2">
|
<RestConnectorForm connector={connector} onConnect={onConnect} />
|
||||||
<RestConnectorForm connector={connector} onConnect={onConnect} />
|
</div>
|
||||||
</div>
|
|
||||||
</ConnectDialogContent>
|
|
||||||
{type === 'hosted' ? (
|
|
||||||
<ConnectDialogFooter>
|
|
||||||
<p className="text-center">
|
|
||||||
{t('For demo purposes get a ')}
|
|
||||||
<Link
|
|
||||||
href={ExternalLinks.VEGA_WALLET_HOSTED_URL}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
{t('hosted wallet')}
|
|
||||||
</Link>
|
|
||||||
{t(', or for the real experience create a wallet in the ')}
|
|
||||||
<Link href={ExternalLinks.VEGA_WALLET_URL}>
|
|
||||||
{t('Vega wallet app')}
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
</ConnectDialogFooter>
|
|
||||||
) : (
|
|
||||||
<ConnectDialogFooter />
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connector instanceof JsonRpcConnector) {
|
if (connector instanceof JsonRpcConnector) {
|
||||||
return (
|
return (
|
||||||
<ConnectDialogContent>
|
<JsonRpcConnectorForm
|
||||||
<JsonRpcConnectorForm
|
connector={connector}
|
||||||
connector={connector}
|
status={jsonRpcState.status}
|
||||||
status={jsonRpcState.status}
|
error={jsonRpcState.error}
|
||||||
error={jsonRpcState.error}
|
onConnect={onConnect}
|
||||||
onConnect={onConnect}
|
appChainId={appChainId}
|
||||||
appChainId={appChainId}
|
reset={reset}
|
||||||
reset={reset}
|
riskMessage={riskMessage}
|
||||||
riskMessage={riskMessage}
|
/>
|
||||||
/>
|
|
||||||
</ConnectDialogContent>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connector instanceof ViewConnector) {
|
if (connector instanceof ViewConnector) {
|
||||||
return (
|
return (
|
||||||
<>
|
<ViewConnectorForm
|
||||||
<ConnectDialogContent>
|
connector={connector}
|
||||||
<ViewConnectorForm
|
onConnect={onConnect}
|
||||||
connector={connector}
|
reset={reset}
|
||||||
onConnect={onConnect}
|
/>
|
||||||
reset={reset}
|
|
||||||
/>
|
|
||||||
</ConnectDialogContent>
|
|
||||||
<ConnectDialogFooter />
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,12 +333,12 @@ const ConnectionOption = ({
|
|||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
size="lg"
|
size="lg"
|
||||||
fill={true}
|
fill={true}
|
||||||
variant={['hosted', 'view'].includes(type) ? 'default' : 'primary'}
|
variant={['rest', 'view'].includes(type) ? 'default' : 'primary'}
|
||||||
data-testid={`connector-${type}`}
|
data-testid={`connector-${type}`}
|
||||||
>
|
>
|
||||||
<span className="-mx-6 flex text-left justify-between items-center">
|
<span className="-mx-10 flex text-left justify-between items-center">
|
||||||
{text}
|
{text}
|
||||||
<Icon name="chevron-right" />
|
<VegaIcon name={VegaIconNames.ARROW_RIGHT} />
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
@@ -387,9 +354,7 @@ const CustomUrlInput = ({
|
|||||||
const [urlInputExpanded, setUrlInputExpanded] = useState(false);
|
const [urlInputExpanded, setUrlInputExpanded] = useState(false);
|
||||||
return urlInputExpanded ? (
|
return urlInputExpanded ? (
|
||||||
<>
|
<>
|
||||||
<p className="mb-2 text-neutral-600 dark:text-neutral-400">
|
<p className="mb-2">{t('Custom wallet location')}</p>
|
||||||
{t('Custom wallet location')}
|
|
||||||
</p>
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
labelFor="wallet-url"
|
labelFor="wallet-url"
|
||||||
label={t('Custom wallet location')}
|
label={t('Custom wallet location')}
|
||||||
@@ -401,12 +366,10 @@ const CustomUrlInput = ({
|
|||||||
name="wallet-url"
|
name="wallet-url"
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<p className="mb-2 text-neutral-600 dark:text-neutral-400">
|
<p className="mb-2">{t('Choose wallet app to connect')}</p>
|
||||||
{t('Choose wallet app to connect')}
|
|
||||||
</p>
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<p className="mb-6 text-neutral-600 dark:text-neutral-400">
|
<p className="mb-6">
|
||||||
{t(
|
{t(
|
||||||
'Choose wallet app to connect, or to change port or server URL enter a '
|
'Choose wallet app to connect, or to change port or server URL enter a '
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { Status } from '../use-injected-connector';
|
||||||
|
import { ConnectDialogTitle } from './connect-dialog-elements';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
ButtonLink,
|
||||||
|
Diamond,
|
||||||
|
Loader,
|
||||||
|
Tick,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { setAcknowledged } from '../storage';
|
||||||
|
import { useVegaWallet } from '../use-vega-wallet';
|
||||||
|
|
||||||
|
export const InjectedConnectorForm = ({
|
||||||
|
status,
|
||||||
|
onConnect,
|
||||||
|
riskMessage,
|
||||||
|
appChainId,
|
||||||
|
reset,
|
||||||
|
error,
|
||||||
|
}: {
|
||||||
|
// connector: JsonRpcConnector;
|
||||||
|
appChainId: string;
|
||||||
|
status: Status;
|
||||||
|
error: Error | null;
|
||||||
|
onConnect: () => void;
|
||||||
|
reset: () => void;
|
||||||
|
riskMessage?: React.ReactNode;
|
||||||
|
}) => {
|
||||||
|
const { disconnect } = useVegaWallet();
|
||||||
|
|
||||||
|
if (status === Status.Idle) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === Status.Error) {
|
||||||
|
return <Error error={error} appChainId={appChainId} onTryAgain={reset} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === Status.GettingChainId) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ConnectDialogTitle>{t('Verifying chain')}</ConnectDialogTitle>
|
||||||
|
<Center>
|
||||||
|
<Loader />
|
||||||
|
</Center>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === Status.Connected) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ConnectDialogTitle>{t('Successfully connected')}</ConnectDialogTitle>
|
||||||
|
<Center>
|
||||||
|
<Tick />
|
||||||
|
</Center>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === Status.Connecting) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ConnectDialogTitle>{t('Connecting...')}</ConnectDialogTitle>
|
||||||
|
<Center>
|
||||||
|
<Diamond />
|
||||||
|
</Center>
|
||||||
|
<p className="text-center">
|
||||||
|
{t(
|
||||||
|
"Approve the connection from your Vega wallet app. If you have multiple wallets you'll need to choose which to connect with."
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === Status.AcknowledgeNeeded) {
|
||||||
|
const setConnection = () => {
|
||||||
|
setAcknowledged();
|
||||||
|
onConnect();
|
||||||
|
};
|
||||||
|
const handleDisagree = () => {
|
||||||
|
disconnect();
|
||||||
|
onConnect(); // this is dialog closing
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ConnectDialogTitle>{t('Understand the risk')}</ConnectDialogTitle>
|
||||||
|
{riskMessage}
|
||||||
|
<div className="grid grid-cols-2 gap-5">
|
||||||
|
<div>
|
||||||
|
<Button onClick={handleDisagree} fill>
|
||||||
|
{t('Cancel')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button onClick={setConnection} variant="primary" fill>
|
||||||
|
{t('I agree')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Center = ({ children }: { children: ReactNode }) => {
|
||||||
|
return (
|
||||||
|
<div className="flex justify-center items-center my-6">{children}</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Error = ({
|
||||||
|
error,
|
||||||
|
appChainId,
|
||||||
|
onTryAgain,
|
||||||
|
}: {
|
||||||
|
error: Error | null;
|
||||||
|
appChainId: string;
|
||||||
|
onTryAgain: () => void;
|
||||||
|
}) => {
|
||||||
|
let title = t('Something went wrong');
|
||||||
|
let text: ReactNode | undefined = t('An unknown error occurred');
|
||||||
|
const tryAgain: ReactNode | null = (
|
||||||
|
<p className="text-center">
|
||||||
|
<ButtonLink onClick={onTryAgain}>{t('Try again')}</ButtonLink>
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
if (error.message === 'Invalid chain') {
|
||||||
|
title = t('Wrong network');
|
||||||
|
text = t(
|
||||||
|
'To complete your wallet connection, set your wallet network in your app to "%s".',
|
||||||
|
appChainId
|
||||||
|
);
|
||||||
|
} else if (error.message === 'window.vega not found') {
|
||||||
|
title = t('No wallet detected');
|
||||||
|
text = t('Vega browser extension not installed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ConnectDialogTitle>{title}</ConnectDialogTitle>
|
||||||
|
<p className="text-center mb-2 first-letter:uppercase">{text}</p>
|
||||||
|
{tryAgain}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,21 +1,83 @@
|
|||||||
import type { VegaConnector } from './vega-connector';
|
import { clearConfig, setConfig } from '../storage';
|
||||||
|
import type { Transaction, VegaConnector } from './vega-connector';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Vega {
|
||||||
|
getChainId: () => Promise<{ chainID: string }>;
|
||||||
|
connectWallet: () => Promise<null>;
|
||||||
|
disconnectWallet: () => Promise<void>;
|
||||||
|
listKeys: () => Promise<{
|
||||||
|
keys: Array<{ name: string; publicKey: string }>;
|
||||||
|
}>;
|
||||||
|
sendTransaction: (params: {
|
||||||
|
publicKey: string;
|
||||||
|
transaction: Transaction;
|
||||||
|
sendingMode: 'TYPE_SYNC';
|
||||||
|
}) => Promise<{
|
||||||
|
receivedAt: string;
|
||||||
|
sentAt: string;
|
||||||
|
transaction: {
|
||||||
|
from: {
|
||||||
|
pubKey: string;
|
||||||
|
};
|
||||||
|
inputData: string;
|
||||||
|
pow: {
|
||||||
|
tid: string;
|
||||||
|
nonce: string;
|
||||||
|
};
|
||||||
|
signature: {
|
||||||
|
algo: string;
|
||||||
|
value: string;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
transactionHash: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
vega: Vega;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Dummy injected connector that we may use when browser wallet is implemented
|
|
||||||
*/
|
|
||||||
export class InjectedConnector implements VegaConnector {
|
export class InjectedConnector implements VegaConnector {
|
||||||
description = 'Connects using the Vega wallet browser extension';
|
description = 'Connects using the Vega wallet browser extension';
|
||||||
|
|
||||||
|
async getChainId() {
|
||||||
|
return window.vega.getChainId();
|
||||||
|
}
|
||||||
|
|
||||||
|
connectWallet() {
|
||||||
|
return window.vega.connectWallet();
|
||||||
|
}
|
||||||
|
|
||||||
async connect() {
|
async connect() {
|
||||||
return [{ publicKey: '0x123', name: 'text key' }];
|
const res = await window.vega.listKeys();
|
||||||
|
setConfig({
|
||||||
|
connector: 'injected',
|
||||||
|
token: null, // no token required for injected
|
||||||
|
url: null, // no url for injected
|
||||||
|
});
|
||||||
|
return res.keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
async disconnect() {
|
disconnect() {
|
||||||
return;
|
clearConfig();
|
||||||
|
return window.vega.disconnectWallet();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore injected connector is not implemented
|
async sendTx(pubKey: string, transaction: Transaction) {
|
||||||
sendTx() {
|
const result = await window.vega.sendTransaction({
|
||||||
throw new Error('Not implemented');
|
publicKey: pubKey,
|
||||||
|
transaction,
|
||||||
|
sendingMode: 'TYPE_SYNC' as const,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
transactionHash: result.transactionHash,
|
||||||
|
receivedAt: result.receivedAt,
|
||||||
|
sentAt: result.sentAt,
|
||||||
|
signature: result.transaction.signature.value,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ export interface OrderSubmission {
|
|||||||
expiresAt?: string;
|
expiresAt?: string;
|
||||||
postOnly?: boolean;
|
postOnly?: boolean;
|
||||||
reduceOnly?: boolean;
|
reduceOnly?: boolean;
|
||||||
|
icebergOpts?: {
|
||||||
|
peakSize: string;
|
||||||
|
minimumVisibleSize: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderCancellation {
|
export interface OrderCancellation {
|
||||||
@@ -411,7 +415,7 @@ export interface PubKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface VegaConnector {
|
export interface VegaConnector {
|
||||||
url: string | null;
|
url?: string | null;
|
||||||
|
|
||||||
/** Connect to wallet and return keys */
|
/** Connect to wallet and return keys */
|
||||||
connect(): Promise<PubKey[] | null>;
|
connect(): Promise<PubKey[] | null>;
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ export const VegaWalletProvider = ({ children }: VegaWalletProviderProps) => {
|
|||||||
if (!connector.current) {
|
if (!connector.current) {
|
||||||
throw new Error('No connector');
|
throw new Error('No connector');
|
||||||
}
|
}
|
||||||
|
|
||||||
return connector.current.sendTx(pubkey, transaction);
|
return connector.current.sendTx(pubkey, transaction);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { LocalStorage } from '@vegaprotocol/utils';
|
|||||||
|
|
||||||
interface ConnectorConfig {
|
interface ConnectorConfig {
|
||||||
token: string | null;
|
token: string | null;
|
||||||
connector: 'rest' | 'jsonRpc' | 'view';
|
connector: 'injected' | 'rest' | 'jsonRpc' | 'view';
|
||||||
url: string | null;
|
url: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
export function mockBrowserWallet(overrides?: Partial<Vega>) {
|
||||||
|
const vega: Vega = {
|
||||||
|
getChainId: jest.fn().mockReturnValue(Promise.resolve({ chainID: '1' })),
|
||||||
|
connectWallet: jest.fn().mockReturnValue(Promise.resolve(null)),
|
||||||
|
disconnectWallet: jest.fn().mockReturnValue(Promise.resolve()),
|
||||||
|
listKeys: jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValue({ keys: [{ name: 'test key', publicKey: '0x123' }] }),
|
||||||
|
sendTransaction: jest.fn().mockReturnValue({
|
||||||
|
code: 1,
|
||||||
|
data: '',
|
||||||
|
height: '1',
|
||||||
|
log: '',
|
||||||
|
success: true,
|
||||||
|
txHash: '0x123',
|
||||||
|
}),
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
// @ts-ignore globalThis has no index signature
|
||||||
|
globalThis.vega = vega;
|
||||||
|
return vega;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearBrowserWallet() {
|
||||||
|
// @ts-ignore no index signature on globalThis
|
||||||
|
delete globalThis['vega'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function delayedResolve<T>(result: T, delay = 0): Promise<T> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => resolve(result), delay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function delayedReject<T>(result: T, delay = 0): Promise<T> {
|
||||||
|
return new Promise((_, reject) => {
|
||||||
|
setTimeout(() => reject(result), delay);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -31,7 +31,14 @@ export function useEagerConnect(Connectors: {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await connect(Connectors[cfg.connector]);
|
if (cfg.connector === 'injected') {
|
||||||
|
const injectedInstance = Connectors[cfg.connector];
|
||||||
|
// @ts-ignore only injected wallet has connectWallet method
|
||||||
|
await injectedInstance.connectWallet();
|
||||||
|
await connect(injectedInstance);
|
||||||
|
} else {
|
||||||
|
await connect(Connectors[cfg.connector]);
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
console.warn(`Failed to connect with connector: ${cfg.connector}`);
|
console.warn(`Failed to connect with connector: ${cfg.connector}`);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import { act, renderHook, waitFor } from '@testing-library/react';
|
||||||
|
import { Status, useInjectedConnector } from './use-injected-connector';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
import { VegaWalletProvider } from './provider';
|
||||||
|
import { InjectedConnector } from './connectors';
|
||||||
|
import { mockBrowserWallet } from './test-helpers';
|
||||||
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
|
import { Networks } from '@vegaprotocol/environment';
|
||||||
|
|
||||||
|
jest.mock('@vegaprotocol/environment');
|
||||||
|
|
||||||
|
const setup = (callback = jest.fn()) => {
|
||||||
|
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
|
<VegaWalletProvider>{children}</VegaWalletProvider>
|
||||||
|
);
|
||||||
|
return renderHook(() => useInjectedConnector(callback), { wrapper });
|
||||||
|
};
|
||||||
|
|
||||||
|
const injected = new InjectedConnector();
|
||||||
|
|
||||||
|
describe('useInjectedConnector', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
// @ts-ignore useEnvironment has been mocked
|
||||||
|
useEnvironment.mockImplementation(() => ({ VEGA_ENV: Networks.TESTNET }));
|
||||||
|
});
|
||||||
|
it('attempts connection', async () => {
|
||||||
|
const { result } = setup();
|
||||||
|
expect(typeof result.current.connect).toBe('function');
|
||||||
|
expect(result.current.status).toBe(Status.Idle);
|
||||||
|
expect(result.current.error).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors if vega not injected', async () => {
|
||||||
|
const { result } = setup();
|
||||||
|
await act(async () => {
|
||||||
|
result.current.connect(injected, '1');
|
||||||
|
});
|
||||||
|
expect(result.current.error?.message).toBe('window.vega not found');
|
||||||
|
expect(result.current.status).toBe(Status.Error);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors if chain ids dont match', async () => {
|
||||||
|
mockBrowserWallet();
|
||||||
|
const { result } = setup();
|
||||||
|
await act(async () => {
|
||||||
|
result.current.connect(injected, '2'); // default mock chainId is '1'
|
||||||
|
});
|
||||||
|
expect(result.current.error?.message).toBe('Invalid chain');
|
||||||
|
expect(result.current.status).toBe(Status.Error);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors if connection throws', async () => {
|
||||||
|
const callback = jest.fn();
|
||||||
|
mockBrowserWallet({
|
||||||
|
getChainId: () => Promise.reject('failed'),
|
||||||
|
});
|
||||||
|
const { result } = setup(callback);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
result.current.connect(injected, '1'); // default mock chainId is '1'
|
||||||
|
});
|
||||||
|
expect(result.current.status).toBe(Status.Error);
|
||||||
|
expect(result.current.error?.message).toBe('injected connection failed');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('connects', async () => {
|
||||||
|
const callback = jest.fn();
|
||||||
|
const vega = mockBrowserWallet();
|
||||||
|
const { result } = setup(callback);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
result.current.connect(injected, '1'); // default mock chainId is '1'
|
||||||
|
});
|
||||||
|
expect(result.current.status).toBe(Status.GettingChainId);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(vega.connectWallet).toHaveBeenCalled();
|
||||||
|
expect(vega.listKeys).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.current.status).toBe(Status.Connected);
|
||||||
|
expect(callback).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('connects when aknowledgement required', async () => {
|
||||||
|
const callback = jest.fn();
|
||||||
|
// @ts-ignore useEnvironment has been mocked
|
||||||
|
useEnvironment.mockImplementation(() => ({ VEGA_ENV: Networks.MAINNET }));
|
||||||
|
|
||||||
|
const vega = mockBrowserWallet();
|
||||||
|
const { result } = setup(callback);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
result.current.connect(injected, '1'); // default mock chainId is '1'
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(vega.listKeys).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.current.status).toBe(Status.AcknowledgeNeeded);
|
||||||
|
expect(callback).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import type { InjectedConnector } from './connectors';
|
||||||
|
import { useVegaWallet } from './use-vega-wallet';
|
||||||
|
|
||||||
|
export enum Status {
|
||||||
|
Idle = 'Idle',
|
||||||
|
GettingChainId = 'GettingChainId',
|
||||||
|
Connecting = 'Connecting',
|
||||||
|
Connected = 'Connected',
|
||||||
|
Error = 'Error',
|
||||||
|
AcknowledgeNeeded = 'AcknowledgeNeeded',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useInjectedConnector = (onConnect: () => void) => {
|
||||||
|
const { connect, acknowledgeNeeded } = useVegaWallet();
|
||||||
|
const [status, setStatus] = useState(Status.Idle);
|
||||||
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
|
||||||
|
const attemptConnect = useCallback(
|
||||||
|
async (connector: InjectedConnector, appChainId: string) => {
|
||||||
|
try {
|
||||||
|
if (!('vega' in window)) {
|
||||||
|
throw new Error('window.vega not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatus(Status.GettingChainId);
|
||||||
|
|
||||||
|
const { chainID } = await connector.getChainId();
|
||||||
|
|
||||||
|
if (chainID !== appChainId) {
|
||||||
|
throw new Error('Invalid chain');
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatus(Status.Connecting);
|
||||||
|
await connector.connectWallet(); // authorize wallet
|
||||||
|
await connect(connector); // connect with keys
|
||||||
|
|
||||||
|
if (acknowledgeNeeded) {
|
||||||
|
setStatus(Status.AcknowledgeNeeded);
|
||||||
|
} else {
|
||||||
|
setStatus(Status.Connected);
|
||||||
|
onConnect();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof Error) {
|
||||||
|
setError(err);
|
||||||
|
} else {
|
||||||
|
setError(new Error('injected connection failed'));
|
||||||
|
}
|
||||||
|
setStatus(Status.Error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[acknowledgeNeeded, connect, onConnect]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
status,
|
||||||
|
error,
|
||||||
|
connect: attemptConnect,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -11,7 +11,6 @@ export enum Status {
|
|||||||
GettingChainId = 'GettingChainId',
|
GettingChainId = 'GettingChainId',
|
||||||
Connecting = 'Connecting',
|
Connecting = 'Connecting',
|
||||||
GettingPerms = 'GettingPerms',
|
GettingPerms = 'GettingPerms',
|
||||||
ListingKeys = 'ListingKeys',
|
|
||||||
Connected = 'Connected',
|
Connected = 'Connected',
|
||||||
Error = 'Error',
|
Error = 'Error',
|
||||||
AcknowledgeNeeded = 'AcknowledgeNeeded',
|
AcknowledgeNeeded = 'AcknowledgeNeeded',
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
from os import environ
|
||||||
|
from subprocess import check_output
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
import json
|
||||||
|
|
||||||
|
projects = []
|
||||||
|
projects_e2e = []
|
||||||
|
|
||||||
|
previews = {
|
||||||
|
'governance': 'not deployed',
|
||||||
|
'explorer': 'not deployed',
|
||||||
|
'trading': 'not deployed',
|
||||||
|
'tools': 'not deployed',
|
||||||
|
}
|
||||||
|
|
||||||
|
main_apps = ['governance', 'explorer', 'trading']
|
||||||
|
|
||||||
|
preview_governance="not deployed"
|
||||||
|
preview_trading="not deployed"
|
||||||
|
preview_explorer="not deployed"
|
||||||
|
preview_tools="not deployed"
|
||||||
|
|
||||||
|
# take input from the pipeline
|
||||||
|
parser = ArgumentParser()
|
||||||
|
|
||||||
|
# let's generate slug from bash spell for now
|
||||||
|
parser.add_argument('--branch-slug', help='slug of branch')
|
||||||
|
parser.add_argument('--github-ref', help='current github ref')
|
||||||
|
parser.add_argument('--event-name', help='name of event in CI')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# run yarn affected command
|
||||||
|
affected=check_output(f'yarn nx print-affected --base={environ["NX_BASE"]} --head={environ["NX_HEAD"]} --select=projects'.split()).decode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
# print useful information
|
||||||
|
print(">>>> debug")
|
||||||
|
print(f"NX_BASE: { environ['NX_BASE'] }")
|
||||||
|
print(f"NX_HEAD: { environ['NX_HEAD'] }")
|
||||||
|
print(f"Branch slug: {args.branch_slug}")
|
||||||
|
print(f"Current ref: {args.github_ref}")
|
||||||
|
print(">> Affected output")
|
||||||
|
print(affected)
|
||||||
|
print(">>>> eof debug")
|
||||||
|
|
||||||
|
# define affection actions -> add to projects arrays and generate preview link
|
||||||
|
def affect_app(app, preview_name=None):
|
||||||
|
print(f"{app} is affected")
|
||||||
|
projects.append(app)
|
||||||
|
if not preview_name:
|
||||||
|
preview_name=app
|
||||||
|
previews[app] = f'https://{preview_name}.{args.branch_slug}.vega.rocks'
|
||||||
|
|
||||||
|
# check appearance in the affected string for main apps
|
||||||
|
for app in main_apps:
|
||||||
|
if app in affected:
|
||||||
|
affect_app(app)
|
||||||
|
|
||||||
|
# if non of main apps is affected - test all of them
|
||||||
|
if not projects:
|
||||||
|
for app in main_apps:
|
||||||
|
affect_app(app)
|
||||||
|
|
||||||
|
# generate e2e targets
|
||||||
|
projects_e2e = [f'{app}-e2e' for app in projects]
|
||||||
|
|
||||||
|
# check affection for multisig-signer which is deployed only from develop and pull requests
|
||||||
|
if args.event_name == 'pull_request' or 'develop' in args.github_ref:
|
||||||
|
if 'multisig-signer' in affected:
|
||||||
|
affect_app('multisig-signer', 'tools')
|
||||||
|
|
||||||
|
# now parse apps that are deployed from develop but don't have previews
|
||||||
|
if 'develop' in args.github_ref:
|
||||||
|
for app in ['static', 'ui-toolkit']:
|
||||||
|
if app in affected:
|
||||||
|
projects.append(app)
|
||||||
|
|
||||||
|
# if ref is in format release/{env}-{app} then only {app} is deployed
|
||||||
|
if 'release' in args.github_ref:
|
||||||
|
for app in main_apps:
|
||||||
|
if f'{args.github_ref}'.endswith(app):
|
||||||
|
projects = [app]
|
||||||
|
projects_e2e = [f'{app}-e2e']
|
||||||
|
|
||||||
|
|
||||||
|
projects = json.dumps(projects)
|
||||||
|
projects_e2e = json.dumps(projects_e2e)
|
||||||
|
|
||||||
|
print(f'Projects: {projects}')
|
||||||
|
print(f'Projects E2E: {projects_e2e}')
|
||||||
|
|
||||||
|
print('>> Previews')
|
||||||
|
for preview, preview_value in previews.items():
|
||||||
|
print(f'{preview}: {preview_value}')
|
||||||
|
print('>> EOF Previews')
|
||||||
|
|
||||||
|
|
||||||
|
lines_to_write = [
|
||||||
|
f'PREVIEW_GOVERNANCE={previews["governance"]}',
|
||||||
|
f'PREVIEW_EXPLORER={previews["explorer"]}',
|
||||||
|
f'PREVIEW_TRADING={previews["trading"]}',
|
||||||
|
f'PREVIEW_TOOLS={previews["tools"]}',
|
||||||
|
f'PROJECTS={projects}',
|
||||||
|
f'PROJECTS_E2E={projects_e2e}',
|
||||||
|
]
|
||||||
|
env_file = environ['GITHUB_ENV']
|
||||||
|
print(f'Line to add to GITHUB_ENV file: {env_file}')
|
||||||
|
print(lines_to_write)
|
||||||
|
with open(env_file, 'a') as _f:
|
||||||
|
_f.write('\n'.join(lines_to_write))
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
from argparse import ArgumentParser
|
||||||
|
from os import environ
|
||||||
|
|
||||||
|
# take input from the pipeline
|
||||||
|
parser = ArgumentParser()
|
||||||
|
|
||||||
|
# let's generate slug from bash spell for now
|
||||||
|
parser.add_argument('--github-ref', help='current github ref')
|
||||||
|
parser.add_argument('--app', help='current app')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
env_name = ''
|
||||||
|
domain = 'vega.rocks'
|
||||||
|
bucket_name = ''
|
||||||
|
|
||||||
|
if 'release/' in args.github_ref:
|
||||||
|
if 'mainnet-mirror' in args.github_ref:
|
||||||
|
env_name = 'mainnet-mirror'
|
||||||
|
if 'validators-testnet' in args.github_ref:
|
||||||
|
env_name = 'validators-testnet'
|
||||||
|
else:
|
||||||
|
# remove prefixing release/ and take the first string limited by - which is supposed to be name of the environment for releasing (format: release/testnet-trading)
|
||||||
|
env_name = args.github_ref.replace('refs/heads/release/', '').split('-')[0]
|
||||||
|
elif 'develop' in args.github_ref:
|
||||||
|
env_name = 'stagnet1'
|
||||||
|
apps_deployed_from_develop_to_mainnet = {
|
||||||
|
'multisig-signer' :'tools.vega.xyz',
|
||||||
|
'static': 'static.vega.xyz',
|
||||||
|
'ui-toolkit' : 'ui.vega.rocks',
|
||||||
|
}
|
||||||
|
if args.app in apps_deployed_from_develop_to_mainnet:
|
||||||
|
env_name = 'mainnet'
|
||||||
|
bucket_name = apps_deployed_from_develop_to_mainnet[args.app]
|
||||||
|
# endswith to avoid confusion with mirror env
|
||||||
|
elif args.github_ref.endswith('mainnet'):
|
||||||
|
env_name = 'mainnet'
|
||||||
|
|
||||||
|
|
||||||
|
other_domains_to_deploy = {
|
||||||
|
'mainnet': 'vega.xyz',
|
||||||
|
'testnet': 'fairground.wtf',
|
||||||
|
}
|
||||||
|
|
||||||
|
if env_name in other_domains_to_deploy:
|
||||||
|
domain = other_domains_to_deploy[env_name]
|
||||||
|
if not bucket_name:
|
||||||
|
bucket_name = f'{args.app}.{domain}'
|
||||||
|
|
||||||
|
# testing envs on vega.rocks contain env_name in the url not like testnet / mainnet
|
||||||
|
if not bucket_name:
|
||||||
|
bucket_name = f'{args.app}.{env_name}.{domain}'
|
||||||
|
|
||||||
|
print(f'env name: {env_name}')
|
||||||
|
print(f'domain: {domain}')
|
||||||
|
print(f'bucket name: {bucket_name}')
|
||||||
|
|
||||||
|
lines_to_write = [
|
||||||
|
f'ENV_NAME={env_name}',
|
||||||
|
f'BUCKET_NAME={bucket_name}',
|
||||||
|
]
|
||||||
|
|
||||||
|
env_file = environ['GITHUB_ENV']
|
||||||
|
print(f'Line to add to GITHUB_ENV file: {env_file}')
|
||||||
|
print(lines_to_write)
|
||||||
|
with open(env_file, 'a') as _f:
|
||||||
|
_f.write('\n'.join(lines_to_write))
|
||||||
Reference in New Issue
Block a user