Compare commits

..
80 changed files with 1586 additions and 1412 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ env:
jobs:
add_issue:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: 'Add issue to project board'
run: |
+1 -1
View File
@@ -13,7 +13,7 @@ on:
jobs:
cypress-run:
name: Run Cypress Trading tests -- live environment
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
+1 -1
View File
@@ -1,4 +1,4 @@
name: (CI) Cypress Run
name: Cypress Run
on:
workflow_call:
inputs:
+9 -12
View File
@@ -8,25 +8,22 @@ on:
jobs:
master:
name: Generate Queries
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
uses: actions/checkout@v2
with:
node-version-file: '.nvmrc'
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
cache: yarn
fetch-depth: 0
- name: Use Node.js 16
id: Node
uses: actions/setup-node@v2
with:
node-version: 16.15.1
- name: Install root dependencies
run: yarn install --frozen-lockfile
run: yarn install
- name: Generate queries
run: node ./scripts/get-queries.js
- uses: actions/upload-artifact@v2
with:
name: queries
+10 -17
View File
@@ -3,28 +3,21 @@ name: Verify PR title
on:
pull_request:
types:
- opened
- ready_for_review
- reopened
- edited
- synchronize
types: [opened, ready_for_review, reopened, edited, synchronize]
jobs:
lint_pr:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
uses: actions/checkout@v2
with:
node-version-file: '.nvmrc'
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
cache: yarn
fetch-depth: 0
- name: Use Node.js 16
id: Node
uses: actions/setup-node@v2
with:
node-version: 16.15.1
- name: Install root dependencies
run: yarn install --frozen-lockfile
run: yarn install
- name: Check PR title
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
@@ -1,9 +1,10 @@
name: CI/CD
name: PR Validations
on:
push:
branches:
- release/*
- develop
- main
pull_request:
types:
- opened
@@ -11,55 +12,42 @@ on:
- synchronize
- ready_for_review
jobs:
lint-test-build:
runs-on: ubuntu-22.04
name: '(CI) lint + unit test + build'
pr:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Check node version
id: node-version
run: |
npmVersion=$(cat .nvmrc | head -n 1)
echo ::set-output name=npmVersion::${npmVersion}
- 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
- name: Install root dependencies
run: yarn install --frozen-lockfile
node-version: ${{ steps.node-version.outputs.npmVersion }}
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v3
with:
main-branch-name: develop
- name: Check formatting
run: yarn nx format:check
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: '**/node_modules'
key: node_modules-${{ hashFiles('**/yarn.lock') }}
- name: Lint affected
run: yarn nx affected:lint --max-warnings=0
- name: Install root dependencies
run: yarn install --frozen-lockfile
- name: Build affected spec
run: yarn nx affected --target=build-spec
- name: Test affected
run: yarn nx affected:test
- name: Build affected
run: yarn nx affected:build
# See affected apps
- name: See affected apps
run: |
echo ">>>> debug"
echo "NX Version: $nx_version"
echo "NX_BASE: ${{ env.NX_BASE }}"
echo "NX_HEAD: ${{ env.NX_HEAD }}"
echo ">>>> eof debug"
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)"
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=HEAD --select=projects)"
echo -n "Affected projects: $affected"
projects_e2e=""
@@ -76,33 +64,32 @@ jobs:
projects: ${{ env.PROJECTS }}
projects-e2e: ${{ env.PROJECTS_E2E }}
cypress:
needs: lint-test-build
name: '(CI) cypress'
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
run-cypress:
needs: pr
if: ${{ needs.pr.outputs.projects != '[]' }}
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
with:
projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
projects: ${{ needs.pr.outputs.projects-e2e }}
tags: '@smoke @regression'
publish-dist:
needs: lint-test-build
name: '(CD) publish dist'
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
uses: ./.github/workflows/publish-dist.yml
run-docker-build:
needs: pr
if: ${{ needs.pr.outputs.projects != '[]' }}
uses: ./.github/workflows/publish-docker-containers.yml
secrets: inherit
with:
projects: ${{ needs.lint-test-build.outputs.projects }}
projects: ${{ needs.pr.outputs.projects }}
# Report single result at the end, to avoid mess with required checks in PR
cypress-result:
result:
if: ${{ always() }}
needs: cypress
runs-on: ubuntu-22.04
needs: run-cypress
runs-on: ubuntu-latest
name: Cypress result
steps:
- run: |
result="${{ needs.cypress.result }}"
result="${{ needs.run-cypress.result }}"
if [[ $result == "success" || $result == "skipped" ]]; then
exit 0
else
+1 -1
View File
@@ -7,7 +7,7 @@ on:
jobs:
master:
name: Generate Queries
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Checkout
@@ -1,4 +1,4 @@
name: (CD) Publish docker + s3
name: Docker build
on:
workflow_call:
@@ -8,13 +8,13 @@ on:
type: string
jobs:
publish-dist:
master:
strategy:
fail-fast: false
matrix:
app: ${{ fromJSON(inputs.projects) }}
name: ${{ matrix.app }}
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
@@ -29,6 +29,41 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# https://docs.github.com/en/actions/learn-github-actions/contexts
# https://github.com/actions/checkout#Checkout-pull-request-HEAD-commit-instead-of-merge-commit
- name: Determine Docker Image tag
id: tags
run: |
npmVersion=$(cat .nvmrc | head -n 1)
versionTag=${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || github.event.pull_request.head.sha }}
echo ::set-output name=npmVersion::${npmVersion}
echo ::set-output name=version::${versionTag}
- name: Print config
run: |
git rev-parse --verify HEAD
git status
echo "steps.tags.outputs.version=${{ steps.tags.outputs.version }}"
- name: Build and export to local Docker
uses: docker/build-push-action@v3
with:
load: true
build-args: |
APP=${{ matrix.app }}
NODE_VERSION=${{ steps.tags.outputs.npmVersion }}
tags: |
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
- name: Sanity check docker image
run: |
echo "Check .env file"
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat .env
echo "Check ipfs-hash"
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat ipfs-hash
echo "List html directory"
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local ls -lah
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
@@ -36,66 +71,17 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# https://docs.github.com/en/actions/learn-github-actions/contexts
- name: Check node version
id: tags
run: |
nodeVersion=$(cat .nvmrc | head -n 1)
echo ::set-output name=nodeVersion::${nodeVersion}
if [[ "${{ github.event_name }}" = "push" ]]; then
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
bucketName="${{ github.event.repository.name }}-$envName"
echo ::set-output name=bucketName::${bucketName}
echo ::set-output name=envName::${envName}
fi
- name: Build and export to local Docker
- name: Build and push
id: docker_build
uses: docker/build-push-action@v3
with:
load: true
build-args: |
APP=${{ matrix.app }}
NODE_VERSION=${{ steps.tags.outputs.nodeVersion }}
ENV_NAME=${{ steps.tags.outputs.envName || '' }}
tags: |
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
- name: Sanity check docker image
run: |
echo "Check ipfs-hash"
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat ipfs-hash
echo "List html directory"
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local ls -lah
echo "Copy dist to local filesystem"
docker create --name=dist ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
docker cp dist:/usr/share/nginx/html dist
echo "Check local dist"
ls -al dist
- name: Publish dist as docker image
uses: docker/build-push-action@v3
if: ${{ github.event_name == 'pull_request' }}
with:
push: true
build-args: |
APP=${{ matrix.app }}
NODE_VERSION=${{ steps.tags.outputs.nodeVersion }}
NODE_VERSION=${{ steps.tags.outputs.npmVersion }}
tags: |
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ github.event.pull_request.head.sha || github.sha }}
# - uses: shallwefootball/s3-upload-action@master
# if: ${{ github.event_name == 'push' }}
# name: Upload dist S3
# with:
# aws_key_id: ${{ secrets.AWS_KEY_ID }}
# aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY}}
# aws_bucket: ${{ steps.tags.outputs.bucketName }}
# source_dir: 'dist'
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:latest
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ steps.tags.outputs.version }}
- name: Add preview label
uses: actions-ecosystem/action-add-labels@v1
+11 -9
View File
@@ -19,27 +19,29 @@ on:
jobs:
publish:
name: Build & Publish - Tag
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
permissions:
contents: 'read'
actions: 'read'
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup node
with:
fetch-depth: 0
- name: User Node.js 16
id: 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
node-version: 16.15.1
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: '**/node_modules'
key: node_modules-${{ hashFiles('**/yarn.lock') }}
- name: Install root dependencies
run: yarn install --frozen-lockfile
- name: Build project
run: yarn nx build ${{inputs.project}}
- name: Publish project to @vegaprotocol
uses: JS-DevTools/npm-publish@v1
with:
+46
View File
@@ -0,0 +1,46 @@
name: Unit tests & build
on:
push:
branches:
- develop
- main
pull_request:
jobs:
pr:
name: Test and lint - PR
runs-on: ubuntu-latest
permissions:
contents: 'read'
actions: 'read'
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v2
with:
main-branch-name: ${{ github.base_ref }}
- name: Use Node.js 16
id: Node
uses: actions/setup-node@v3
with:
node-version: 16.15.1
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: '**/node_modules'
key: node_modules-${{ hashFiles('**/yarn.lock') }}
- name: Install root dependencies
run: yarn install --frozen-lockfile
- name: Check formatting
run: yarn nx format:check
- name: Lint affected
run: yarn nx affected:lint --max-warnings=0
- name: Test affected
run: yarn nx affected:test
- name: Build affected
run: yarn nx affected:build
- name: Build affected spec
run: yarn nx affected --target=build-spec
+7 -2
View File
@@ -4,7 +4,6 @@ FROM --platform=amd64 node:${NODE_VERSION}-alpine3.16 as build
WORKDIR /app
# Argument to allow building of different apps
ARG APP
ARG ENV_NAME=""
RUN apk add --update --no-cache \
python3 \
make \
@@ -19,10 +18,16 @@ RUN sh ./docker-build.sh
# if this fails you need to docker pull nginx:1.23-alpine and pin new SHA
# this is to ensure that we run always same version of alpine to make sure ipfs is indempotent
FROM --platform=amd64 nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
ARG APP
# configuration of system
RUN apk add --no-cache bash go-ipfs
EXPOSE 80
COPY entrypoint.sh /entrypoint.sh
CMD ["/entrypoint.sh"]
# Copy dist
WORKDIR /usr/share/nginx/html
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist/apps/${APP} /usr/share/nginx/html
RUN apk add --no-cache go-ipfs; ipfs init && echo "$(ipfs add -rQ .)" > ipfs-hash; apk del go-ipfs
COPY ./apps/${APP}/.env .env
RUN ipfs init && echo "$(ipfs add -rQ .)" > ipfs-hash
+1 -1
View File
@@ -1,7 +1,7 @@
NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n00.stagnet3.vega.xyz/websocket
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
NX_VEGA_NETWORKS='{"STAGNET1":"https://stagnet1.token.vega.xyz", "STAGNET3":"https://stagnet3.explorer.vega.xyz","VALIDATOR_TESTNET":"https://validator-testnet.fairground.wtf","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_NETWORKS='{"SANDBOX":"https://sandbox.explorer.vega.xyz","STAGNET1":"https://stagnet1.token.vega.xyz", "STAGNET3":"https://stagnet3.explorer.vega.xyz","VALIDATOR_TESTNET":"https://validator-testnet.fairground.wtf","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_ENV=STAGNET3
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
+20
View File
@@ -0,0 +1,20 @@
# App configuration variables
NX_TENDERMINT_URL=https://tm.be.mainnet-mirror.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.xyz/websocket
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
NX_VEGA_ENV=MIRROR
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.xyz/rest/
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://mainnet-mirror.token.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
# App flags
NX_EXPLORER_ASSETS=1
NX_EXPLORER_GENESIS=1
NX_EXPLORER_GOVERNANCE=1
NX_EXPLORER_NETWORK_PARAMETERS=1
NX_EXPLORER_PARTIES=1
NX_EXPLORER_VALIDATORS=1
NX_EXPLORER_MARKETS=0
NX_EXPLORER_ORACLES=0
NX_EXPLORER_TXS_LIST=1
+12
View File
@@ -0,0 +1,12 @@
# App configuration variables
NX_VEGA_ENV=SANDBOX
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/sandbox/vegawallet-sandbox.toml
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_TENDERMINT_URL=https://tm.sandbox.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.sandbox.vega.xyz/websocket
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://sandbox.token.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
+1 -1
View File
@@ -9,5 +9,5 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
NX_VEGA_GOVERNANCE_URL=https://validator-testnet.governance.vega.xyz
NX_TENDERMINT_URL=https://tm-be.validators-testnet.vega.rocks
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
+12
View File
@@ -0,0 +1,12 @@
# App configuration variables
NX_VEGA_ENV=MIRROR
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
NX_VEGA_URL=https://api.n00.mainnet-mirror.vega.xyz/graphql
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_VEGA_EXPLORER_URL=https://mirror.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_DELEGATIONS_PAGINATION=50
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
+9
View File
@@ -0,0 +1,9 @@
# App configuration variables
NX_VEGA_URL=https://api.sandbox.vega.xyz/graphql
NX_VEGA_ENV=SANDBOX
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","STAGNET1":"https://stagnet1.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/sandbox/vegawallet-sandbox.toml
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
-1
View File
@@ -8,4 +8,3 @@ NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
+8 -4
View File
@@ -12,7 +12,6 @@ const TRUTHY = ['1', 'true'];
interface VegaContracts {
claimAddress: string;
lockedAddress: string;
tokenVestingAddress?: string;
}
const customClaimAddress = process.env['NX_CUSTOM_CLAIM_ADDRESS'] as string;
@@ -37,16 +36,21 @@ export const ContractAddresses: {
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
lockedAddress: '0x0', // TODO not deployed to this env
},
SANDBOX: {
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
lockedAddress: '0x0', // TODO not deployed to this env
},
TESTNET: {
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
lockedAddress: '0x0', // TODO not deployed to this env
},
MIRROR: {
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
lockedAddress: '0x0', // TODO not deployed to this env
},
VALIDATOR_TESTNET: {
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
lockedAddress: '0x0', // TODO not deployed to this env
// This is a fallback contract address for the validator testnet network which does not
// have a vesting contract address set and is therefore not in the ethereum config
tokenVestingAddress: '0xadFcb7f93a24F8743a8e548d74d2ecB373c92866',
},
MAINNET: {
claimAddress: '0x0ee1fb382caf98e86e97e51f9f42f8b4654020f3',
@@ -49,13 +49,6 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
signer = provider.getSigner();
}
const tokenVestingAddress =
config.token_vesting_contract?.address ||
ENV.addresses.tokenVestingAddress;
if (!tokenVestingAddress) {
throw new Error('No token vesting address found');
}
if (provider && config) {
const staking = new StakingBridge(
config.staking_bridge_contract.address,
@@ -70,7 +63,7 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
signer || provider
),
vesting: new TokenVesting(
tokenVestingAddress,
config.token_vesting_contract.address,
signer || provider
),
claim: new Claim(ENV.addresses.claimAddress, signer || provider),
@@ -14,7 +14,6 @@ import { TokenDetailsCirculating } from './token-details-circulating';
import { SplashLoader } from '../../../components/splash-loader';
import { useEthereumConfig } from '@vegaprotocol/web3';
import { useContracts } from '../../../contexts/contracts/contracts-context';
import { ENV } from '../../../config';
export const TokenDetails = ({
totalSupply,
@@ -50,9 +49,6 @@ export const TokenDetails = ({
);
}
const tokenVestingContractAddress =
config.token_vesting_contract?.address || ENV.addresses.tokenVestingAddress;
return (
<div className="token-details">
<RoundedWrapper>
@@ -69,20 +65,18 @@ export const TokenDetails = ({
{token.address}
</Link>
</KeyValueTableRow>
{tokenVestingContractAddress && (
<KeyValueTableRow>
{t('Vesting contract').toUpperCase()}
<Link
data-testid="token-contract"
title={t('View on Etherscan (opens in a new tab)')}
className="font-mono text-white text-right"
href={`${ETHERSCAN_URL}/address/${tokenVestingContractAddress}`}
target="_blank"
>
{tokenVestingContractAddress}
</Link>
</KeyValueTableRow>
)}
<KeyValueTableRow>
{t('Vesting contract').toUpperCase()}
<Link
data-testid="token-contract"
title={t('View on Etherscan (opens in a new tab)')}
className="font-mono text-white text-right"
href={`${ETHERSCAN_URL}/address/${config.token_vesting_contract.address}`}
target="_blank"
>
{config.token_vesting_contract.address}
</Link>
</KeyValueTableRow>
<KeyValueTableRow>
{t('Total supply').toUpperCase()}
<span className="font-mono" data-testid="total-supply">
+5
View File
@@ -0,0 +1,5 @@
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/sandbox/vegawallet-sandbox.toml
NX_VEGA_URL=https://api.sandbox.vega.xyz/graphql
NX_VEGA_ENV=SANDBOX
NX_VEGA_NETWORKS={\"DEVNET\":\"https://dev.token.vega.xyz\",\"STAGNET3\":\"https://stagnet3.token.vega.xyz\",\"STAGNET1\":\"https://stagnet1.token.vega.xyz\",\"TESTNET\":\"https://token.fairground.wtf\",\"MAINNET\":\"https://token.vega.xyz\"}
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/sandbox/vegawallet-sandbox.toml
+62 -514
View File
@@ -3,194 +3,12 @@
"tranche_id": 56,
"tranche_start": "2023-04-20T00:00:00.000Z",
"tranche_end": "2023-05-20T00:00:00.000Z",
"total_added": "12395.75",
"total_added": "0",
"total_removed": "0",
"locked_amount": "12395.75",
"deposits": [
{
"amount": "50",
"user": "0x15024E62134A8BFFCce11f5ce58CeCDe853038D7",
"tx": "0xc38d2e52912f15452c76b863dbfad88927b49435c284eaf6997be4cf13782fc0"
},
{
"amount": "6001.25",
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
"tx": "0xde2c8eedaba7ef1c953a7ca5439a8d7900ff01d92bd49d9dff1c9cdeaaa38d6f"
},
{
"amount": "2378.75",
"user": "0xd5EAB7ecE436D997139dbCd2c38bCE932B65a8ea",
"tx": "0x79d5279a108f5621488b5fba2e0b4c1508fff80bd3cf7bd36f8d79f5a87f9fea"
},
{
"amount": "1121.25",
"user": "0xf96afaB11e5617560b9183766470B23F45c38C56",
"tx": "0xd75c7996c5a9484ad3432eab458341b21eb76e117d68fb2885170bfb7b017da1"
},
{
"amount": "1121.25",
"user": "0xf915Da10e5136352Ba049acB0545Deb119054256",
"tx": "0x6840e2b579765303fc31a04f43fcea1d5ccf157b46bbd1e3f3e7f6a2e6cea039"
},
{
"amount": "51.75",
"user": "0x237D23FcA6d7B2530C7614a9cB921CF27924911E",
"tx": "0x3e9c304b5ca74d1238cc4ee2f1396812aac6e62eb8674e8be3e01c9ad3e5bcb0"
},
{
"amount": "379.5",
"user": "0x6536B87D6a31a37645c2E0E948BB1a2166FAcdaE",
"tx": "0x6dc1c78046509fc85f149ad55a0683e059f46d53eab51397ff202c22ee55938f"
},
{
"amount": "138",
"user": "0x9f709F2b44e14B2832832FC35aC378e41Bf14bBC",
"tx": "0x1b2921c481d2af4dead917173e4fc821ca119bc9408460caff9c25ae09e06a3d"
},
{
"amount": "1154",
"user": "0x981D29D939cAa4ADC04A5e44224dBB45539E8730",
"tx": "0x3e8baadb612f97fd9fa0b4a8f28c57381d87ff43a083117e19d0332e37869a7f"
}
],
"locked_amount": "0",
"deposits": [],
"withdrawals": [],
"users": [
{
"address": "0x15024E62134A8BFFCce11f5ce58CeCDe853038D7",
"deposits": [
{
"amount": "50",
"user": "0x15024E62134A8BFFCce11f5ce58CeCDe853038D7",
"tranche_id": 56,
"tx": "0xc38d2e52912f15452c76b863dbfad88927b49435c284eaf6997be4cf13782fc0"
}
],
"withdrawals": [],
"total_tokens": "50",
"withdrawn_tokens": "0",
"remaining_tokens": "50"
},
{
"address": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
"deposits": [
{
"amount": "6001.25",
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
"tranche_id": 56,
"tx": "0xde2c8eedaba7ef1c953a7ca5439a8d7900ff01d92bd49d9dff1c9cdeaaa38d6f"
}
],
"withdrawals": [],
"total_tokens": "6001.25",
"withdrawn_tokens": "0",
"remaining_tokens": "6001.25"
},
{
"address": "0xd5EAB7ecE436D997139dbCd2c38bCE932B65a8ea",
"deposits": [
{
"amount": "2378.75",
"user": "0xd5EAB7ecE436D997139dbCd2c38bCE932B65a8ea",
"tranche_id": 56,
"tx": "0x79d5279a108f5621488b5fba2e0b4c1508fff80bd3cf7bd36f8d79f5a87f9fea"
}
],
"withdrawals": [],
"total_tokens": "2378.75",
"withdrawn_tokens": "0",
"remaining_tokens": "2378.75"
},
{
"address": "0xf96afaB11e5617560b9183766470B23F45c38C56",
"deposits": [
{
"amount": "1121.25",
"user": "0xf96afaB11e5617560b9183766470B23F45c38C56",
"tranche_id": 56,
"tx": "0xd75c7996c5a9484ad3432eab458341b21eb76e117d68fb2885170bfb7b017da1"
}
],
"withdrawals": [],
"total_tokens": "1121.25",
"withdrawn_tokens": "0",
"remaining_tokens": "1121.25"
},
{
"address": "0xf915Da10e5136352Ba049acB0545Deb119054256",
"deposits": [
{
"amount": "1121.25",
"user": "0xf915Da10e5136352Ba049acB0545Deb119054256",
"tranche_id": 56,
"tx": "0x6840e2b579765303fc31a04f43fcea1d5ccf157b46bbd1e3f3e7f6a2e6cea039"
}
],
"withdrawals": [],
"total_tokens": "1121.25",
"withdrawn_tokens": "0",
"remaining_tokens": "1121.25"
},
{
"address": "0x237D23FcA6d7B2530C7614a9cB921CF27924911E",
"deposits": [
{
"amount": "51.75",
"user": "0x237D23FcA6d7B2530C7614a9cB921CF27924911E",
"tranche_id": 56,
"tx": "0x3e9c304b5ca74d1238cc4ee2f1396812aac6e62eb8674e8be3e01c9ad3e5bcb0"
}
],
"withdrawals": [],
"total_tokens": "51.75",
"withdrawn_tokens": "0",
"remaining_tokens": "51.75"
},
{
"address": "0x6536B87D6a31a37645c2E0E948BB1a2166FAcdaE",
"deposits": [
{
"amount": "379.5",
"user": "0x6536B87D6a31a37645c2E0E948BB1a2166FAcdaE",
"tranche_id": 56,
"tx": "0x6dc1c78046509fc85f149ad55a0683e059f46d53eab51397ff202c22ee55938f"
}
],
"withdrawals": [],
"total_tokens": "379.5",
"withdrawn_tokens": "0",
"remaining_tokens": "379.5"
},
{
"address": "0x9f709F2b44e14B2832832FC35aC378e41Bf14bBC",
"deposits": [
{
"amount": "138",
"user": "0x9f709F2b44e14B2832832FC35aC378e41Bf14bBC",
"tranche_id": 56,
"tx": "0x1b2921c481d2af4dead917173e4fc821ca119bc9408460caff9c25ae09e06a3d"
}
],
"withdrawals": [],
"total_tokens": "138",
"withdrawn_tokens": "0",
"remaining_tokens": "138"
},
{
"address": "0x981D29D939cAa4ADC04A5e44224dBB45539E8730",
"deposits": [
{
"amount": "1154",
"user": "0x981D29D939cAa4ADC04A5e44224dBB45539E8730",
"tranche_id": 56,
"tx": "0x3e8baadb612f97fd9fa0b4a8f28c57381d87ff43a083117e19d0332e37869a7f"
}
],
"withdrawals": [],
"total_tokens": "1154",
"withdrawn_tokens": "0",
"remaining_tokens": "1154"
}
]
"users": []
},
{
"tranche_id": 55,
@@ -249,9 +67,9 @@
"tranche_id": 54,
"tranche_start": "2023-04-06T00:00:00.000Z",
"tranche_end": "2023-05-06T00:00:00.000Z",
"total_added": "8565",
"total_added": "2970",
"total_removed": "0",
"locked_amount": "8565",
"locked_amount": "2970",
"deposits": [
{
"amount": "33",
@@ -268,21 +86,6 @@
"user": "0xE9F41a0090fcc7eaf626037003AAD44B17098E7C",
"tx": "0x09d3e968eb8dbd6851f47b36f7bb9e7d25a078c5c1b23ce5341a66ce19578e65"
},
{
"amount": "678",
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
"tx": "0x157b13e78d027a5b6cf35fdae80a8cec7797149f35c23eb43faa07d74a03d70d"
},
{
"amount": "2394",
"user": "0xd5EAB7ecE436D997139dbCd2c38bCE932B65a8ea",
"tx": "0xbe03bd7e16faa3586fe66ddaac2bcacba4604b175721eb10aee29b40248759ea"
},
{
"amount": "2523",
"user": "0xf96afaB11e5617560b9183766470B23F45c38C56",
"tx": "0x49ab3f37bda02347cb1966e8fa21885a463f09d0593a890e96b2e36dfb8dec49"
},
{
"amount": "111",
"user": "0x268070d5EEd5b24E34a5F4C17B5482178b18089D",
@@ -411,51 +214,6 @@
"withdrawn_tokens": "0",
"remaining_tokens": "288"
},
{
"address": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
"deposits": [
{
"amount": "678",
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
"tranche_id": 54,
"tx": "0x157b13e78d027a5b6cf35fdae80a8cec7797149f35c23eb43faa07d74a03d70d"
}
],
"withdrawals": [],
"total_tokens": "678",
"withdrawn_tokens": "0",
"remaining_tokens": "678"
},
{
"address": "0xd5EAB7ecE436D997139dbCd2c38bCE932B65a8ea",
"deposits": [
{
"amount": "2394",
"user": "0xd5EAB7ecE436D997139dbCd2c38bCE932B65a8ea",
"tranche_id": 54,
"tx": "0xbe03bd7e16faa3586fe66ddaac2bcacba4604b175721eb10aee29b40248759ea"
}
],
"withdrawals": [],
"total_tokens": "2394",
"withdrawn_tokens": "0",
"remaining_tokens": "2394"
},
{
"address": "0xf96afaB11e5617560b9183766470B23F45c38C56",
"deposits": [
{
"amount": "2523",
"user": "0xf96afaB11e5617560b9183766470B23F45c38C56",
"tranche_id": 54,
"tx": "0x49ab3f37bda02347cb1966e8fa21885a463f09d0593a890e96b2e36dfb8dec49"
}
],
"withdrawals": [],
"total_tokens": "2523",
"withdrawn_tokens": "0",
"remaining_tokens": "2523"
},
{
"address": "0x268070d5EEd5b24E34a5F4C17B5482178b18089D",
"deposits": [
@@ -803,7 +561,7 @@
"tranche_end": "2023-04-06T00:00:00.000Z",
"total_added": "14099",
"total_removed": "165.10784124668",
"locked_amount": "110.66430592891317977",
"locked_amount": "1247.56462776284332054",
"deposits": [
{
"amount": "30",
@@ -3591,7 +3349,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "86666.297",
"total_removed": "0",
"locked_amount": "57756.158813300075873473",
"locked_amount": "58349.7031275271807221145",
"deposits": [
{
"amount": "86666.297",
@@ -3657,7 +3415,7 @@
"tranche_end": "2023-06-01T00:00:00.000Z",
"total_added": "2500",
"total_removed": "0",
"locked_amount": "772.573101088726",
"locked_amount": "806.91026276963785",
"deposits": [
{
"amount": "2500",
@@ -3778,7 +3536,7 @@
"tranche_end": "2023-09-01T00:00:00.000Z",
"total_added": "17500",
"total_removed": "0",
"locked_amount": "14099.22897166868",
"locked_amount": "14336.97649330716525",
"deposits": [
{
"amount": "12500",
@@ -4044,8 +3802,8 @@
"tranche_start": "2023-02-01T00:00:00.000Z",
"tranche_end": "2023-08-01T00:00:00.000Z",
"total_added": "37500",
"total_removed": "11781.2245815",
"locked_amount": "24290.74345841006625",
"total_removed": "11668.32172695",
"locked_amount": "24808.64650475752125",
"deposits": [
{
"amount": "7500",
@@ -4079,11 +3837,6 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xf440dd4b160a155a08a3cc6e16706d5e4f9609bddd46c495217c377ef538c76f"
},
{
"amount": "112.90285455",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x69a4b32bad0a702a9e19ec1a77e4bc75d936f323720ca4c6213f2e4f41a750ed"
},
{
"amount": "92.587476975",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -4210,12 +3963,6 @@
"tranche_id": 34,
"tx": "0xf440dd4b160a155a08a3cc6e16706d5e4f9609bddd46c495217c377ef538c76f"
},
{
"amount": "112.90285455",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 34,
"tx": "0x69a4b32bad0a702a9e19ec1a77e4bc75d936f323720ca4c6213f2e4f41a750ed"
},
{
"amount": "92.587476975",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -4326,8 +4073,8 @@
}
],
"total_tokens": "7500",
"withdrawn_tokens": "2545.7753031",
"remaining_tokens": "4954.2246969"
"withdrawn_tokens": "2432.87244855",
"remaining_tokens": "5067.12755145"
},
{
"address": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
@@ -4365,7 +4112,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "129999.45",
"total_removed": "0",
"locked_amount": "57703.463585541498254355",
"locked_amount": "58296.4663652644736979915",
"deposits": [
{
"amount": "129999.45",
@@ -4398,7 +4145,7 @@
"tranche_end": "2024-04-01T00:00:00.000Z",
"total_added": "54144.7663",
"total_removed": "0",
"locked_amount": "53441.07987456501837419469",
"locked_amount": "53810.8835054071292707386",
"deposits": [
{
"amount": "54144.7663",
@@ -4431,7 +4178,7 @@
"tranche_end": "2023-09-03T00:00:00.000Z",
"total_added": "62600",
"total_removed": "0",
"locked_amount": "25767.75874556062762",
"locked_amount": "26196.482198122780824",
"deposits": [
{
"amount": "10000",
@@ -4624,7 +4371,7 @@
"tranche_end": "2023-09-17T00:00:00.000Z",
"total_added": "5000",
"total_removed": "0",
"locked_amount": "2249.908517250127",
"locked_amount": "2284.15160451547415",
"deposits": [
{
"amount": "5000",
@@ -4835,7 +4582,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "97499.58",
"total_removed": "0",
"locked_amount": "0",
"locked_amount": "405.60456575344483061187",
"deposits": [
{
"amount": "97499.58",
@@ -4868,7 +4615,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "135173.4239508",
"total_removed": "133818.54965292963650862",
"locked_amount": "0",
"locked_amount": "554.3914166779487086967342868",
"deposits": [
{
"amount": "135173.4239508",
@@ -4925,7 +4672,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "32499.86",
"total_removed": "0",
"locked_amount": "0",
"locked_amount": "170.63083639627856110929",
"deposits": [
{
"amount": "32499.86",
@@ -4958,7 +4705,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "10833.29",
"total_removed": "0",
"locked_amount": "0",
"locked_amount": "55.53868148454478352929",
"deposits": [
{
"amount": "10833.29",
@@ -4991,7 +4738,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "22749.93",
"total_removed": "4720.860935375",
"locked_amount": "0",
"locked_amount": "207.61599572971184611278",
"deposits": [
{
"amount": "6500",
@@ -5142,8 +4889,8 @@
"tranche_start": "2022-11-01T00:00:00.000Z",
"tranche_end": "2023-05-01T00:00:00.000Z",
"total_added": "22500",
"total_removed": "6357.929999175",
"locked_amount": "3137.98198664825145",
"total_removed": "6244.98110415",
"locked_amount": "3448.723814456722875",
"deposits": [
{
"amount": "7500",
@@ -5172,16 +4919,6 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x0e47007cb85268a4e0c3c1143b96e4c98c9880060c4218babcadd0c82f8247a9"
},
{
"amount": "112.943139975",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xde2d6d5df9d5097adf8a894beb8a02f0bd1cc4da1eccc221f8bfa08403dfed87"
},
{
"amount": "0.00575505",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xa7a9a0e91b78fd7d8ba4c16bf5b58fb1a3cb19ec1302788e894f5e24ccb07904"
},
{
"amount": "92.593232025",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -5363,18 +5100,6 @@
"tranche_id": 33,
"tx": "0x0e47007cb85268a4e0c3c1143b96e4c98c9880060c4218babcadd0c82f8247a9"
},
{
"amount": "112.943139975",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 33,
"tx": "0xde2d6d5df9d5097adf8a894beb8a02f0bd1cc4da1eccc221f8bfa08403dfed87"
},
{
"amount": "0.00575505",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 33,
"tx": "0xa7a9a0e91b78fd7d8ba4c16bf5b58fb1a3cb19ec1302788e894f5e24ccb07904"
},
{
"amount": "92.593232025",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -5557,8 +5282,8 @@
}
],
"total_tokens": "7500",
"withdrawn_tokens": "6357.929999175",
"remaining_tokens": "1142.070000825"
"withdrawn_tokens": "6244.98110415",
"remaining_tokens": "1255.01889585"
},
{
"address": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1",
@@ -5583,7 +5308,7 @@
"tranche_end": "2023-06-02T00:00:00.000Z",
"total_added": "1939928.38",
"total_removed": "928642.9598472029154",
"locked_amount": "304240.943688379690701449",
"locked_amount": "317526.7710493525900617104",
"deposits": [
{
"amount": "1852091.69",
@@ -11071,7 +10796,7 @@
"tranche_id": 11,
"tranche_start": "2021-09-03T00:00:00.000Z",
"tranche_end": "2022-09-03T00:00:00.000Z",
"total_added": "57238.000000000000000003",
"total_added": "57213.000000000000000003",
"total_removed": "48157.21518131551",
"locked_amount": "0",
"deposits": [
@@ -11095,11 +10820,6 @@
"user": "0x363D3d06d70761c34D6EfEB25E409A9549E6970D",
"tx": "0x180cd3aca2d716aa233483a9a52b02e83d9ac88716ca85d998269965c7a01a96"
},
{
"amount": "25",
"user": "0x981D29D939cAa4ADC04A5e44224dBB45539E8730",
"tx": "0xac528ad2b9d958135e7556c5d9d36ce97eb6fb723dd44b3430374276e0fae9be"
},
{
"amount": "150",
"user": "0xEb01fF124D71b6C7E6613fd6E0A86c28C733F008",
@@ -22903,21 +22623,6 @@
"withdrawn_tokens": "0",
"remaining_tokens": "25"
},
{
"address": "0x981D29D939cAa4ADC04A5e44224dBB45539E8730",
"deposits": [
{
"amount": "25",
"user": "0x981D29D939cAa4ADC04A5e44224dBB45539E8730",
"tranche_id": 11,
"tx": "0xac528ad2b9d958135e7556c5d9d36ce97eb6fb723dd44b3430374276e0fae9be"
}
],
"withdrawals": [],
"total_tokens": "25",
"withdrawn_tokens": "0",
"remaining_tokens": "25"
},
{
"address": "0xEb01fF124D71b6C7E6613fd6E0A86c28C733F008",
"deposits": [
@@ -39336,7 +39041,7 @@
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "3732368.4671",
"total_removed": "700133.348465855088393",
"locked_amount": "492013.729732206686798975272",
"locked_amount": "512429.420752227829460135708",
"deposits": [
{
"amount": "1998.95815",
@@ -40717,8 +40422,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "15870102.715470999700000001",
"total_removed": "815921.67873801845247952",
"locked_amount": "7044336.6809704508767487714278225047431739",
"total_removed": "814470.78267520605435452",
"locked_amount": "7116729.41051479466949006868895061288618547",
"deposits": [
{
"amount": "16249.93",
@@ -41252,21 +40957,6 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x58bac20de3636c17156dcb64322cc7612c48f553d941bc039c796ef4167eeeb5"
},
{
"amount": "481.17190713062625",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x625ce40117b67b756a12ad676cfbfd2c59e264b3c86adbc624bf7107c4dbc5d5"
},
{
"amount": "462.457470607163625",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xa65322922116e2e0949be9d83e65ef0b1f2d8fe3eb399616a5cbbb7c95593717"
},
{
"amount": "507.26668507460825",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x8be0ce3e72ef8b69c5682a9272305c5adfc68fa2d082381f47ae13e917a6cef8"
},
{
"amount": "545.4204142199725",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -43291,24 +42981,6 @@
"tranche_id": 2,
"tx": "0x58bac20de3636c17156dcb64322cc7612c48f553d941bc039c796ef4167eeeb5"
},
{
"amount": "481.17190713062625",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0x625ce40117b67b756a12ad676cfbfd2c59e264b3c86adbc624bf7107c4dbc5d5"
},
{
"amount": "462.457470607163625",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0xa65322922116e2e0949be9d83e65ef0b1f2d8fe3eb399616a5cbbb7c95593717"
},
{
"amount": "507.26668507460825",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0x8be0ce3e72ef8b69c5682a9272305c5adfc68fa2d082381f47ae13e917a6cef8"
},
{
"amount": "545.4204142199725",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -44685,8 +44357,8 @@
}
],
"total_tokens": "259998.8875",
"withdrawn_tokens": "144465.698336257346125",
"remaining_tokens": "115533.189163742653875"
"withdrawn_tokens": "143014.802273444948",
"remaining_tokens": "116984.085226555052"
},
{
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
@@ -47031,8 +46703,8 @@
"tranche_start": "2021-11-05T00:00:00.000Z",
"tranche_end": "2023-05-05T00:00:00.000Z",
"total_added": "14597706.0446472999",
"total_removed": "5808173.326897276766376406",
"locked_amount": "781841.4190672246241239369447994325",
"total_removed": "5802489.518043560526965506",
"locked_amount": "848673.9247506211806821697552292785",
"deposits": [
{
"amount": "129284.449",
@@ -47296,26 +46968,6 @@
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xae9047ab72d73da1001c570a12dddc5e82fd523454c1b377928e008da9bdfa85"
},
{
"amount": "3666.3885480971028369",
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
"tx": "0x54687b81b06562122894e34822a416021671c28f99066a23c5a69399b614409d"
},
{
"amount": "661.66343451005891275",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x523cbf99fb25ac9633e40a26cf1aa66ac5442392e577299159bf50e844a860e1"
},
{
"amount": "646.042220779495735",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xcd3480c11e987e702a52413185dcc232b399747ef2fd7529aa46bea02c6f4be5"
},
{
"amount": "709.71465032958192625",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x0464f4416616032385d6cecf639d1b1b8f3d75beab762529d23688456a170602"
},
{
"amount": "755.482067130393772",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -50482,24 +50134,6 @@
"tranche_id": 3,
"tx": "0xae9047ab72d73da1001c570a12dddc5e82fd523454c1b377928e008da9bdfa85"
},
{
"amount": "661.66343451005891275",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0x523cbf99fb25ac9633e40a26cf1aa66ac5442392e577299159bf50e844a860e1"
},
{
"amount": "646.042220779495735",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0xcd3480c11e987e702a52413185dcc232b399747ef2fd7529aa46bea02c6f4be5"
},
{
"amount": "709.71465032958192625",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0x0464f4416616032385d6cecf639d1b1b8f3d75beab762529d23688456a170602"
},
{
"amount": "755.482067130393772",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -53178,8 +52812,8 @@
}
],
"total_tokens": "359123.469575",
"withdrawn_tokens": "339719.996781712978353",
"remaining_tokens": "19403.472793287021647"
"withdrawn_tokens": "337702.576476093841779",
"remaining_tokens": "21420.893098906158221"
},
{
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
@@ -53439,12 +53073,6 @@
"tranche_id": 3,
"tx": "0x14811c8d77a39b0331cb2fdc96049b462916877050cc73143c494277304c2496"
},
{
"amount": "3666.3885480971028369",
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
"tranche_id": 3,
"tx": "0x54687b81b06562122894e34822a416021671c28f99066a23c5a69399b614409d"
},
{
"amount": "80421.5336580481619385",
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
@@ -53777,8 +53405,8 @@
}
],
"total_tokens": "1266324.603486",
"withdrawn_tokens": "1192935.92480528973552942",
"remaining_tokens": "73388.67868071026447058"
"withdrawn_tokens": "1189269.53625719263269252",
"remaining_tokens": "77055.06722880736730748"
},
{
"address": "0xC5d9221EB9c28A69859264c0A2Fe0d3272228296",
@@ -54606,8 +54234,8 @@
"tranche_start": "2021-10-05T00:00:00.000Z",
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "5778205.3912159303",
"total_removed": "3421590.665302980803025769",
"locked_amount": "0",
"total_removed": "3381706.364737906998719578",
"locked_amount": "18412.7968659549219832486449580318",
"deposits": [
{
"amount": "552496.6455",
@@ -54751,26 +54379,6 @@
}
],
"withdrawals": [
{
"amount": "10509.407528939748325",
"user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75",
"tx": "0x621a569bfd19dbc0a6ba78addf836a9f2f1897258a88198d994e5b18c9f4901e"
},
{
"amount": "13312.213609122936225",
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
"tx": "0x8a1d50991be09f4adc9eba704fbbcd271e8022db56498b300f39d3111bf187ea"
},
{
"amount": "13385.167736021049216341",
"user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d",
"tx": "0xa6c475d9dc04d4f722ead66481243b19a2eaafac7d81b4b3bc711a8269a52259"
},
{
"amount": "2677.51169099007053985",
"user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D",
"tx": "0x5d28a9be9d82440733d43afac61bcf6ff79024f1f73d621aa1d3afdba072db4c"
},
{
"amount": "8511.948415174862415",
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
@@ -55768,12 +55376,6 @@
}
],
"withdrawals": [
{
"amount": "10509.407528939748325",
"user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75",
"tranche_id": 4,
"tx": "0x621a569bfd19dbc0a6ba78addf836a9f2f1897258a88198d994e5b18c9f4901e"
},
{
"amount": "990.74735267405816",
"user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75",
@@ -55878,8 +55480,8 @@
}
],
"total_tokens": "110499.5291",
"withdrawn_tokens": "110307.617158818603845",
"remaining_tokens": "191.911941181396155"
"withdrawn_tokens": "99798.20962987885552",
"remaining_tokens": "10701.31947012114448"
},
{
"address": "0xdbC5d439F373EB646345e1c67D1d46231ACE7dD3",
@@ -55920,12 +55522,6 @@
}
],
"withdrawals": [
{
"amount": "2677.51169099007053985",
"user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D",
"tranche_id": 4,
"tx": "0x5d28a9be9d82440733d43afac61bcf6ff79024f1f73d621aa1d3afdba072db4c"
},
{
"amount": "3239.30329480758879835",
"user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D",
@@ -56030,8 +55626,8 @@
}
],
"total_tokens": "92082.572555",
"withdrawn_tokens": "92064.7311274626806437",
"remaining_tokens": "17.8414275373193563"
"withdrawn_tokens": "89387.21943647261010385",
"remaining_tokens": "2695.35311852738989615"
},
{
"address": "0x1dC9B91DE003fd503F25cB5d114cf0fc68F7aFe6",
@@ -56059,12 +55655,6 @@
}
],
"withdrawals": [
{
"amount": "13385.167736021049216341",
"user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d",
"tranche_id": 4,
"tx": "0xa6c475d9dc04d4f722ead66481243b19a2eaafac7d81b4b3bc711a8269a52259"
},
{
"amount": "16197.295646834677510988",
"user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d",
@@ -56193,8 +55783,8 @@
}
],
"total_tokens": "460415.072915097",
"withdrawn_tokens": "460324.930117256149193663",
"remaining_tokens": "90.142797840850806337"
"withdrawn_tokens": "446939.762381235099977322",
"remaining_tokens": "13475.310533861900022678"
},
{
"address": "0xd66e4853c0880df150e7329974715BFC8d2da47D",
@@ -56409,12 +55999,6 @@
}
],
"withdrawals": [
{
"amount": "13312.213609122936225",
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
"tranche_id": 4,
"tx": "0x8a1d50991be09f4adc9eba704fbbcd271e8022db56498b300f39d3111bf187ea"
},
{
"amount": "8511.948415174862415",
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
@@ -56675,8 +56259,8 @@
}
],
"total_tokens": "331498.5873",
"withdrawn_tokens": "331278.641779670288712",
"remaining_tokens": "219.945520329711288"
"withdrawn_tokens": "317966.428170547352487",
"remaining_tokens": "13532.159129452647513"
},
{
"address": "0x16da609341ed67750A8BCC5AAa2005471006Cd77",
@@ -56778,8 +56362,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "472355.6199999996",
"total_removed": "41316.3370079701949",
"locked_amount": "77962.38794645034017680735971588",
"total_removed": "40152.1324861581949",
"locked_amount": "81197.370889637811460062778488072",
"deposits": [
{
"amount": "3000",
@@ -63458,16 +63042,6 @@
"user": "0x28FC83947F02f59Cb36b40f97f2D32BBC5D00585",
"tx": "0x14da65fbf5ae2f3a593036daa58b3353ab88fc22666e5514f9160e252ad2fdf9"
},
{
"amount": "332.441235412",
"user": "0x5c8fadaf56946d60823Dae0526A540EEfE791c99",
"tx": "0x67af8d72b36a27796fbe8f52ac55951d54102ac58582f848f0d21cf8ca427e77"
},
{
"amount": "831.7632864",
"user": "0x9405F540EcC1204801De5C4444D06386BD6693F0",
"tx": "0x0df6ec04cbdda41c8649a5e360ec541d14371e3877d82e1404308180024ede02"
},
{
"amount": "154.812094114",
"user": "0x27e2254A2A8c9c9D1321E5Fe64cAD88e7A4f0ba7",
@@ -68635,17 +68209,10 @@
"tx": "0x1c2c084e3efafb2ffa09c0b259bd229cce0d6da04dd092d911c7e6136a7ac8a9"
}
],
"withdrawals": [
{
"amount": "831.7632864",
"user": "0x9405F540EcC1204801De5C4444D06386BD6693F0",
"tranche_id": 5,
"tx": "0x0df6ec04cbdda41c8649a5e360ec541d14371e3877d82e1404308180024ede02"
}
],
"withdrawals": [],
"total_tokens": "1000",
"withdrawn_tokens": "831.7632864",
"remaining_tokens": "168.2367136"
"withdrawn_tokens": "0",
"remaining_tokens": "1000"
},
{
"address": "0x99b4635De6c5c8cdbBf728d7AA0d1b9DD8Ee381F",
@@ -84482,17 +84049,10 @@
"tx": "0xb59405747c8088945a412703637a7b422f3639439ec2ee15e180c0a2a0d71ee4"
}
],
"withdrawals": [
{
"amount": "332.441235412",
"user": "0x5c8fadaf56946d60823Dae0526A540EEfE791c99",
"tranche_id": 5,
"tx": "0x67af8d72b36a27796fbe8f52ac55951d54102ac58582f848f0d21cf8ca427e77"
}
],
"withdrawals": [],
"total_tokens": "400",
"withdrawn_tokens": "332.441235412",
"remaining_tokens": "67.558764588"
"withdrawn_tokens": "0",
"remaining_tokens": "400"
},
{
"address": "0x96715eF2F036069202B1C8065Db14601F40C9554",
@@ -86340,7 +85900,7 @@
"tranche_start": "2021-12-05T00:00:00.000Z",
"tranche_end": "2022-06-05T00:00:00.000Z",
"total_added": "171288.42",
"total_removed": "68803.5995794947989",
"total_removed": "67553.5995794947989",
"locked_amount": "0",
"deposits": [
{
@@ -90565,11 +90125,6 @@
}
],
"withdrawals": [
{
"amount": "1250",
"user": "0x9405F540EcC1204801De5C4444D06386BD6693F0",
"tx": "0x7dbc1e3f31a7aeea4e74f2bf14137bb99045b84afe7582a9ed2bc9d63b5458a4"
},
{
"amount": "250",
"user": "0x2dd204e9cC4D41C68f2bb7Aa3b8Ce49884e482f5",
@@ -95994,17 +95549,10 @@
"tx": "0x1c2c084e3efafb2ffa09c0b259bd229cce0d6da04dd092d911c7e6136a7ac8a9"
}
],
"withdrawals": [
{
"amount": "1250",
"user": "0x9405F540EcC1204801De5C4444D06386BD6693F0",
"tranche_id": 6,
"tx": "0x7dbc1e3f31a7aeea4e74f2bf14137bb99045b84afe7582a9ed2bc9d63b5458a4"
}
],
"withdrawals": [],
"total_tokens": "1250",
"withdrawn_tokens": "1250",
"remaining_tokens": "0"
"withdrawn_tokens": "0",
"remaining_tokens": "1250"
},
{
"address": "0xf36f5369adBE86DF71f5bFfB0264fc1D99fA2935",
@@ -0,0 +1,3 @@
{
"hosts": ["https://api-n00.mainnet-mirror.vega.rocks/graphql"]
}
@@ -0,0 +1,3 @@
{
"hosts": ["https://api-n01.sandbox.vega.rocks/graphql"]
}
@@ -95,16 +95,6 @@ describe('Console - market info - live env', { tags: '@live' }, () => {
cy.wrap(element).should('have.text', subtitles[index]);
});
});
it('renders correctly liquidity in trading tab', () => {
cy.getByTestId('Liquidity').click();
cy.contains('Loading').should('not.exist');
cy.contains('Something went wrong').should('not.exist');
cy.contains('Application error').should('not.exist');
cy.getByTestId('tab-liquidity').within(() => {
cy.get('[col-id="party.id"]').eq(1).should('not.be.empty');
});
});
});
describe('Console - market summary - live env', { tags: '@live' }, () => {
+163 -41
View File
@@ -1,5 +1,5 @@
import {
matchFilter,
getId,
liquidityProvisionsDataProvider,
LiquidityTable,
lpAggregatedDataProvider,
@@ -17,6 +17,7 @@ import {
useNetworkParams,
updateGridData,
} from '@vegaprotocol/react-helpers';
import * as Schema from '@vegaprotocol/types';
import {
AsyncRenderer,
Tab,
@@ -25,18 +26,19 @@ import {
Indicator,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Header, HeaderStat, HeaderTitle } from '../../components/header';
import type { AgGridReact } from 'ag-grid-react';
import type { IGetRowsParams } from 'ag-grid-community';
import type { LiquidityProvisionData, Filter } from '@vegaprotocol/liquidity';
import type { LiquidityProvisionData } from '@vegaprotocol/liquidity';
import { Link, useParams } from 'react-router-dom';
import { Links, Routes } from '../../pages/client-router';
import { useMarket, useStaticMarketData } from '@vegaprotocol/market-list';
import isEqual from 'lodash/isEqual';
const enum LiquidityTabs {
Active = 'active',
@@ -65,10 +67,8 @@ const useReloadLiquidityData = (marketId: string | undefined) => {
export const LiquidityContainer = ({
marketId,
filter,
}: {
marketId: string | undefined;
filter?: Filter;
}) => {
const gridRef = useRef<AgGridReact | null>(null);
const { data: market } = useMarket(marketId);
@@ -87,7 +87,7 @@ export const LiquidityContainer = ({
const { data, loading, error } = useDataProvider({
dataProvider: lpAggregatedDataProvider,
update,
variables: { marketId: marketId || '', filter },
variables: { marketId: marketId || '' },
skip: !marketId,
});
@@ -216,56 +216,178 @@ const LiquidityViewHeader = memo(({ marketId }: { marketId?: string }) => {
});
LiquidityViewHeader.displayName = 'LiquidityViewHeader';
const filterLiquidities = (
tab: string,
liquidities?: LiquidityProvisionData[] | null,
pubKey?: string | null
) => {
switch (tab) {
case LiquidityTabs.MyLiquidityProvision:
return pubKey
? (liquidities || []).filter((e) => e.party.id === pubKey)
: [];
break;
case LiquidityTabs.Active:
return (liquidities || []).filter(
(e) => e.status === Schema.LiquidityProvisionStatus.STATUS_ACTIVE
);
case LiquidityTabs.Inactive:
return (liquidities || []).filter(
(e) => e.status !== Schema.LiquidityProvisionStatus.STATUS_ACTIVE
);
default:
return [];
}
};
export const LiquidityViewContainer = ({
marketId,
}: {
marketId: string | undefined;
}) => {
const [tab, setTab] = useState<string | undefined>(undefined);
const [tab, setTab] = useState('');
const { pubKey } = useVegaWallet();
const [liquidityProviders, setLiquidityProviders] = useState<
LiquidityProvisionData[] | null
>();
const gridRef = useRef<AgGridReact | null>(null);
const { data: market } = useMarket(marketId);
const dataRef = useRef<LiquidityProvisionData[] | null>(null);
const { data } = useDataProvider({
// To be removed when liquidityProvision subscriptions are working
useReloadLiquidityData(marketId);
const update = useCallback(
({ data }: { data: LiquidityProvisionData[] | null }) => {
if (!dataRef.current) {
setLiquidityProviders(data);
dataRef.current = data;
}
if (!gridRef.current?.api) {
return false;
}
const updateRows: LiquidityProvisionData[] = [];
const addRows: LiquidityProvisionData[] = [];
if (gridRef.current?.api?.getModel().getType() === 'infinite') {
dataRef.current = data;
gridRef.current.api.refreshInfiniteCache();
} else {
const filteredData = filterLiquidities(tab, data, pubKey as string);
filteredData?.forEach((d) => {
const rowNode = gridRef.current?.api?.getRowNode(getId(d));
if (rowNode) {
if (!isEqual(rowNode.data, d)) {
updateRows.push(d);
}
} else {
addRows.push(d);
}
});
gridRef.current?.api?.applyTransaction({
update: updateRows,
add: addRows,
addIndex: 0,
});
}
return true;
},
[gridRef, tab, pubKey]
);
const { loading, error } = useDataProvider({
dataProvider: lpAggregatedDataProvider,
skipUpdates: true,
update,
variables: { marketId: marketId || '' },
skip: !marketId,
});
const assetDecimalPlaces =
market?.tradableInstrument.instrument.product.settlementAsset.decimals || 0;
const symbol =
market?.tradableInstrument.instrument.product.settlementAsset.symbol;
const { params } = useNetworkParams([
NetworkParams.market_liquidity_stakeToCcyVolume,
NetworkParams.market_liquidity_targetstake_triggering_ratio,
]);
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
const myLpEdges = useMemo(
() =>
filterLiquidities(
LiquidityTabs.MyLiquidityProvision,
liquidityProviders,
pubKey
),
[liquidityProviders, pubKey]
);
const activeEdges = useMemo(
() => filterLiquidities(LiquidityTabs.Active, liquidityProviders),
[liquidityProviders]
);
const inactiveEdges = useMemo(
() => filterLiquidities(LiquidityTabs.Inactive, liquidityProviders),
[liquidityProviders]
);
useEffect(() => {
if (data) {
if (pubKey && data.some((lp) => matchFilter({ partyId: pubKey }, lp))) {
setTab(LiquidityTabs.MyLiquidityProvision);
return;
}
if (data.some((lp) => matchFilter({ active: true }, lp))) {
setTab(LiquidityTabs.Active);
return;
}
setTab(LiquidityTabs.Inactive);
if (tab) {
return;
}
}, [data, pubKey]);
let initialTab = LiquidityTabs.Active;
if (myLpEdges.length > 0) {
initialTab = LiquidityTabs.MyLiquidityProvision;
}
if (activeEdges?.length) {
initialTab = LiquidityTabs.Active;
} else if (inactiveEdges.length > 0) {
initialTab = LiquidityTabs.Inactive;
}
setTab(initialTab);
}, [tab, myLpEdges?.length, activeEdges?.length, inactiveEdges?.length]);
return (
<div className="h-full grid grid-rows-[min-content_1fr]">
<LiquidityViewHeader marketId={marketId} />
<Tabs value={tab || LiquidityTabs.Active} onValueChange={setTab}>
<Tab
id={LiquidityTabs.MyLiquidityProvision}
name={t('My liquidity provision')}
hidden={!pubKey}
>
<LiquidityContainer
marketId={marketId}
filter={{ partyId: pubKey || undefined }}
/>
</Tab>
<Tab id={LiquidityTabs.Active} name={t('Active')}>
<LiquidityContainer marketId={marketId} filter={{ active: true }} />
</Tab>
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
<LiquidityContainer marketId={marketId} filter={{ active: false }} />
</Tab>
</Tabs>
</div>
<AsyncRenderer loading={loading} error={error} data={liquidityProviders}>
<div className="h-full grid grid-rows-[min-content_1fr]">
<LiquidityViewHeader marketId={marketId} />
<Tabs value={tab} onValueChange={setTab}>
<Tab
id={LiquidityTabs.MyLiquidityProvision}
name={t('My liquidity provision')}
hidden={!pubKey}
>
{myLpEdges && (
<LiquidityTable
ref={gridRef}
rowData={myLpEdges}
symbol={symbol}
stakeToCcyVolume={stakeToCcyVolume}
assetDecimalPlaces={assetDecimalPlaces}
/>
)}
</Tab>
<Tab id={LiquidityTabs.Active} name={t('Active')}>
{activeEdges && (
<LiquidityTable
ref={gridRef}
rowData={activeEdges}
symbol={symbol}
assetDecimalPlaces={assetDecimalPlaces}
stakeToCcyVolume={stakeToCcyVolume}
/>
)}
</Tab>
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
{inactiveEdges && (
<LiquidityTable
ref={gridRef}
rowData={inactiveEdges}
symbol={symbol}
assetDecimalPlaces={assetDecimalPlaces}
stakeToCcyVolume={stakeToCcyVolume}
/>
)}
</Tab>
</Tabs>
</div>
</AsyncRenderer>
);
};
+5 -1
View File
@@ -23,6 +23,7 @@ import {
} from '@vegaprotocol/ui-toolkit';
import { Links, Routes } from '../../pages/client-router';
import { createDocsLinks } from '@vegaprotocol/utils';
export const Navbar = ({
theme = 'system',
@@ -37,6 +38,7 @@ export const Navbar = ({
const tradingPath = marketId
? Links[Routes.MARKET](marketId)
: Links[Routes.MARKET]();
return (
<Navigation
appName="Console"
@@ -89,7 +91,9 @@ export const Navbar = ({
<NavigationContent>
<NavigationList>
<NavigationItem>
<NavExternalLink href={VEGA_DOCS_URL}>
<NavExternalLink
href={createDocsLinks(VEGA_DOCS_URL).NEW_TO_VEGA}
>
{t('Docs')}
</NavExternalLink>
</NavigationItem>
@@ -474,16 +474,13 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
}
if (tx.order && tx.order.rejectionReason) {
const rejectionReason =
getRejectionReason(tx.order) || tx.order.rejectionReason || '';
const rejectionReason = getRejectionReason(tx.order) || ' ';
return (
<>
<ToastHeading>{t('Order rejected')}</ToastHeading>
{rejectionReason || tx.order.rejectionReason ? (
{rejectionReason ? (
<p>
{t('Your order has been rejected because: %s', [
rejectionReason || tx.order.rejectionReason,
])}
{t('Your order has been rejected because: %s', [rejectionReason])}
</p>
) : (
<p>{t('Your order has been rejected.')}</p>
@@ -582,7 +579,7 @@ const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => {
if (orderRejection) {
label = t('Order rejected');
errorMessage = t('Your order has been rejected because: %s', [
orderRejection || tx.order?.rejectionReason || ' ',
orderRejection,
]);
}
if (walletError) {
@@ -649,11 +646,7 @@ export const useVegaTransactionToasts = () => {
// Transaction can be successful but the order can be rejected by the network
const intent =
(tx.order &&
[OrderStatus.STATUS_REJECTED, OrderStatus.STATUS_STOPPED].includes(
tx.order.status
)) ||
tx.order?.rejectionReason
tx.order && [OrderStatus.STATUS_REJECTED].includes(tx.order.status)
? Intent.Danger
: intentMap[tx.status];
+3 -15
View File
@@ -1,22 +1,10 @@
#!/bin/bash -ex
#!/bin/sh -eux
export PATH="/app/node_modules/.bin:$PATH"
flags="--network-timeout 100000 --pure-lockfile"
if [[ ! -z "${ENV_NAME}" ]]; then
flags="--env=${ENV_NAME} $flags"
fi
if [ "${APP}" = "trading" ]; then
yarn nx export ${APP} $flags
yarn nx export ${APP} --network-timeout 100000 --pure-lockfile
mv /app/dist/apps/trading/exported/ /app/tmp
rm -rf /app/dist/apps/trading
mv /app/tmp /app/dist/apps/trading
else
yarn nx build ${APP} $flags
yarn nx build ${APP} --network-timeout 100000 --pure-lockfile
fi
env_vars_file="/app/dist/apps/${APP}/.env"
# make sure there are no exposed .env files
rm $env_vars_file || echo "No env vars file"
Executable
+43
View File
@@ -0,0 +1,43 @@
#!/bin/bash
set -e
# Recreate config file
env_file=/usr/share/nginx/html/assets/env-config.js
mkdir -p $(dirname $env_file)
rm -rf $env_file || echo "no file to delete"
touch $env_file
env_vars_file=/usr/share/nginx/html/.env
sed -i '/^#/d' $env_vars_file # remove comment lines
sed -i '/^$/d' $env_vars_file # remove empty lines
# Add assignment
echo "window._env_ = {" >> $env_file
# Read each line in .env file
# Each line represents key=value pairs
while read -r line || [[ -n "$line" ]];
do
# Split env variables by character `=`
if printf '%s\n' "$line" | grep -q -e '='; then
varname=$(printf '%s\n' "$line" | sed -e 's/=.*//')
varvalue=$(printf '%s\n' "$line" | sed -e 's/^[^=]*=//')
fi
# Read value of current variable if exists as Environment variable
value=$(printf '%s\n' "${!varname}")
# Otherwise use value from .env file
[[ -z $value ]] && value=${varvalue}
# Append configuration property to JS file if non-empty
if [ ! -z "$varname" ]; then
echo " $varname: \"$value\"," >> $env_file
fi
done < $env_vars_file
rm $env_vars_file
echo "}" >> $env_file
# start serving
nginx -g 'daemon off;'
@@ -1,5 +1,4 @@
import { Tooltip } from '@vegaprotocol/ui-toolkit';
import classnames from 'classnames';
import type { ReactNode } from 'react';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { Market, MarketData } from '@vegaprotocol/market-list';
@@ -12,12 +11,9 @@ interface DealTicketFeeDetailsProps {
order: OrderSubmissionBody['orderSubmission'];
market: Market;
marketData: MarketData;
currentInitialMargin?: string;
currentMaintenanceMargin?: string;
estimatedInitialMargin: string;
estimatedTotalInitialMargin: string;
marginAccountBalance: string;
generalAccountBalance: string;
margin: string;
totalMargin: string;
balance: string;
}
export interface DealTicketFeeDetailProps {
@@ -49,22 +45,23 @@ export const DealTicketFeeDetails = ({
order,
market,
marketData,
...args
margin,
totalMargin,
balance,
}: DealTicketFeeDetailsProps) => {
const feeDetails = useFeeDealTicketDetails(order, market, marketData);
const details = getFeeDetailsValues({
...feeDetails,
...args,
margin,
totalMargin,
balance,
});
return (
<div>
{details.map(({ label, value, labelDescription, symbol, indent }) => (
{details.map(({ label, value, labelDescription, symbol }) => (
<div
key={typeof label === 'string' ? label : 'value-dropdown'}
className={classnames(
'text-xs mt-2 flex justify-between items-center gap-4 flex-wrap',
{ 'ml-2': indent }
)}
className="text-xs mt-2 flex justify-between items-center gap-4 flex-wrap"
>
<div>
<Tooltip description={labelDescription}>
@@ -107,7 +107,7 @@ describe('DealTicket', () => {
);
});
it('should set values for a non-persistent reduce only order and disable post only checkbox', () => {
it('should use local storage state for initial values reduceOnly and postOnly', () => {
const expectedOrder = {
marketId: market.id,
type: Schema.OrderType.TYPE_LIMIT,
@@ -115,7 +115,7 @@ describe('DealTicket', () => {
size: '0.1',
price: '300.22',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
persist: false,
persist: true,
reduceOnly: true,
postOnly: false,
};
@@ -149,58 +149,6 @@ describe('DealTicket', () => {
expect(screen.getByTestId('order-price')).toHaveDisplayValue(
expectedOrder.price
);
expect(screen.getByTestId('post-only')).toBeDisabled();
expect(screen.getByTestId('reduce-only')).toBeEnabled();
expect(screen.getByTestId('reduce-only')).toBeChecked();
expect(screen.getByTestId('post-only')).not.toBeChecked();
});
it('should set values for a persistent post only order and disable reduce only checkbox', () => {
const expectedOrder = {
marketId: market.id,
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
size: '0.1',
price: '300.22',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
persist: true,
reduceOnly: false,
postOnly: true,
};
useOrderStore.setState({
orders: {
[expectedOrder.marketId]: expectedOrder,
},
});
render(generateJsx());
// Assert correct defaults are used from store
expect(
screen
.getByTestId(`order-type-${Schema.OrderType.TYPE_LIMIT}`)
.querySelector('input')
).toBeChecked();
expect(
screen.queryByTestId('order-side-SIDE_SELL')?.querySelector('input')
).toBeChecked();
expect(
screen.queryByTestId('order-side-SIDE_BUY')?.querySelector('input')
).not.toBeChecked();
expect(screen.getByTestId('order-size')).toHaveDisplayValue(
expectedOrder.size
);
expect(screen.getByTestId('order-tif')).toHaveValue(
expectedOrder.timeInForce
);
expect(screen.getByTestId('order-price')).toHaveDisplayValue(
expectedOrder.price
);
expect(screen.getByTestId('post-only')).toBeEnabled();
expect(screen.getByTestId('reduce-only')).toBeDisabled();
expect(screen.getByTestId('post-only')).toBeChecked();
expect(screen.getByTestId('reduce-only')).not.toBeChecked();
});
it('handles TIF select box dependent on order type', async () => {
@@ -44,9 +44,6 @@ import {
import { OrderTimeInForce, OrderType } from '@vegaprotocol/types';
import { useOrderForm } from '../../hooks/use-order-form';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { marketMarginDataProvider } from '@vegaprotocol/positions';
export interface DealTicketProps {
market: Market;
@@ -106,12 +103,6 @@ export const DealTicket = ({
const { margin, totalMargin } = useInitialMargin(market.id, normalizedOrder);
const { data: currentMargins } = useDataProvider({
dataProvider: marketMarginDataProvider,
variables: { marketId: market.id, partyId: pubKey || '' },
skip: !pubKey,
});
useEffect(() => {
if (!pubKey) {
setError('summary', {
@@ -167,16 +158,6 @@ export const DealTicket = ({
return disabled;
}, [order]);
const disableReduceOnlyCheckbox = useMemo(() => {
const disabled = order
? ![
Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
].includes(order.timeInForce)
: true;
return disabled;
}, [order]);
const onSubmit = useCallback(
(order: OrderSubmission) => {
const now = new Date().getTime();
@@ -221,18 +202,8 @@ export const DealTicket = ({
if (type === OrderType.TYPE_NETWORK) return;
update({
type,
// when changing type also update the TIF to what was last used of new type
// when changing type also update the tif to what was last used of new type
timeInForce: lastTIF[type] || order.timeInForce,
postOnly:
type === OrderType.TYPE_MARKET ? false : order.postOnly,
reduceOnly:
type === OrderType.TYPE_LIMIT &&
![
OrderTimeInForce.TIME_IN_FORCE_FOK,
OrderTimeInForce.TIME_IN_FORCE_IOC,
].includes(lastTIF[type] || order.timeInForce)
? false
: order.postOnly,
expiresAt: undefined,
});
clearErrors('expiresAt');
@@ -280,23 +251,8 @@ export const DealTicket = ({
value={order.timeInForce}
orderType={order.type}
onSelect={(timeInForce) => {
// Reset post only and reduce only when changing TIF
update({
timeInForce,
postOnly: [
OrderTimeInForce.TIME_IN_FORCE_FOK,
OrderTimeInForce.TIME_IN_FORCE_IOC,
].includes(timeInForce)
? false
: order.postOnly,
reduceOnly: ![
OrderTimeInForce.TIME_IN_FORCE_FOK,
OrderTimeInForce.TIME_IN_FORCE_IOC,
].includes(timeInForce)
? false
: order.reduceOnly,
});
// Set TIF value for the given order type, so that when switching
update({ timeInForce, postOnly: false, reduceOnly: false });
// Set tif value for the given order type, so that when switching
// types we know the last used TIF for the given order type
setLastTIF((curr) => ({
...curr,
@@ -371,7 +327,6 @@ export const DealTicket = ({
<Checkbox
name="reduce-only"
checked={order.reduceOnly}
disabled={disableReduceOnlyCheckbox}
onCheckedChange={() => {
update({ postOnly: false, reduceOnly: !order.reduceOnly });
}}
@@ -379,13 +334,9 @@ export const DealTicket = ({
<Tooltip
description={
<span>
{disableReduceOnlyCheckbox
? t(
'"Reduce only" can be used only with non-persistent orders, such as "Fill or Kill" or "Immediate or Cancel".'
)
: t(
'"Reduce only" will ensure that this order will not increase the size of an open position. When the order is matched, it will only trade enough volume to bring your open volume towards 0 but never change the direction of your position. If applied to a limit order that is not instantly filled, the order will be stopped.'
)}
{t(
'"Reduce only" will ensure that this order will not increase the size of an open position. When the order is matched, it will only trade enough volume to bring your open volume towards 0 but never change the direction of your position. If applied to a limit order that is not instantly filled, the order will be stopped.'
)}
</span>
}
>
@@ -416,12 +367,9 @@ export const DealTicket = ({
order={normalizedOrder}
market={market}
marketData={marketData}
estimatedInitialMargin={margin}
estimatedTotalInitialMargin={totalMargin}
currentInitialMargin={currentMargins?.initialLevel}
currentMaintenanceMargin={currentMargins?.maintenanceLevel}
marginAccountBalance={marginAccountBalance}
generalAccountBalance={generalAccountBalance}
margin={margin}
totalMargin={totalMargin}
balance={marginAccountBalance}
/>
</form>
</TinyScroll>
+2 -26
View File
@@ -10,36 +10,12 @@ export const EST_MARGIN_TOOLTIP_TEXT = (settlementAsset: string) =>
export const EST_TOTAL_MARGIN_TOOLTIP_TEXT = t(
'Estimated total margin that will cover open position, active orders and this order.'
);
export const MARGIN_ACCOUNT_TOOLTIP_TEXT = t('Margin account balance.');
export const MARGIN_ACCOUNT_TOOLTIP_TEXT = t('Margin account balance');
export const MARGIN_DIFF_TOOLTIP_TEXT = (settlementAsset: string) =>
t(
"The additional margin required for your new position (taking into account volume and open orders), compared to your current margin. Measured in the market's settlement asset (%s).",
[settlementAsset]
);
export const DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT = (
settlementAsset: string
) =>
t(
'To cover the required margin, this amount will be drawn from your general (%s) account.',
[settlementAsset]
);
export const TOTAL_MARGIN_AVAILABLE = (
generalAccountBalance: string,
marginAccountBalance: string,
marginMaintenance: string,
settlementAsset: string
) =>
t(
'Total margin available = general %s balance (%s) + margin balance (%s) - maintenance level (%s).',
[
settlementAsset,
`${generalAccountBalance} ${settlementAsset}`,
`${marginAccountBalance} ${settlementAsset}`,
`${marginMaintenance} ${settlementAsset}`,
]
);
export const CONTRACTS_MARGIN_TOOLTIP_TEXT = t(
'The number of contracts determines how many units of the futures contract to buy or sell. For example, this is similar to buying one share of a listed company. The value of 1 contract is equivalent to the price of the contract. For example, if the current price is $50, then one contract is worth $50.'
);
@@ -64,7 +40,7 @@ export const EST_SLIPPAGE = t(
);
export const ERROR_SIZE_DECIMAL = t(
'The size field accepts up to X decimal places.'
'The size field accepts up to X decimal places'
);
export enum MarketModeValidationType {
@@ -15,8 +15,6 @@ import {
NOTIONAL_SIZE_TOOLTIP_TEXT,
MARGIN_ACCOUNT_TOOLTIP_TEXT,
MARGIN_DIFF_TOOLTIP_TEXT,
DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT,
TOTAL_MARGIN_AVAILABLE,
} from '../constants';
import { useOrderCloseOut } from './use-order-closeout';
import { useMarketAccountBalance } from '@vegaprotocol/accounts';
@@ -87,32 +85,24 @@ export const useFeeDealTicketDetails = (
};
export interface FeeDetails {
generalAccountBalance?: string;
marginAccountBalance?: string;
balance: string;
market: Market;
assetSymbol: string;
notionalSize: string | null;
estCloseOut: string | null;
estimateOrder: EstimateOrderQuery['estimateOrder'] | undefined;
estimatedInitialMargin: string;
estimatedTotalInitialMargin: string;
currentInitialMargin?: string;
currentMaintenanceMargin?: string;
margin: string;
totalMargin: string;
}
export const getFeeDetailsValues = ({
marginAccountBalance,
generalAccountBalance,
balance,
assetSymbol,
estimateOrder,
market,
notionalSize,
estimatedTotalInitialMargin,
currentInitialMargin,
currentMaintenanceMargin,
totalMargin,
}: FeeDetails) => {
const totalBalance =
BigInt(generalAccountBalance || '0') + BigInt(marginAccountBalance || '0');
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const formatValueWithMarketDp = (
@@ -133,8 +123,7 @@ export const getFeeDetailsValues = ({
label: string;
value?: string | null;
symbol: string;
indent?: boolean;
labelDescription?: React.ReactNode;
labelDescription: React.ReactNode;
}[] = [
{
label: t('Notional'),
@@ -164,64 +153,38 @@ export const getFeeDetailsValues = ({
),
symbol: assetSymbol,
},
/*
{
label: t('Initial margin'),
value: margin && `~${formatValueWithAssetDp(margin)}`,
symbol: assetSymbol,
labelDescription: EST_MARGIN_TOOLTIP_TEXT(assetSymbol),
},
*/
{
label: t('Margin required'),
value: `~${formatValueWithAssetDp(
currentInitialMargin
? (
BigInt(estimatedTotalInitialMargin) - BigInt(currentInitialMargin)
).toString()
: estimatedTotalInitialMargin
balance
? (BigInt(totalMargin) - BigInt(balance)).toString()
: totalMargin
)}`,
symbol: assetSymbol,
labelDescription: MARGIN_DIFF_TOOLTIP_TEXT(assetSymbol),
},
];
if (totalBalance) {
const totalMarginAvailable = (
currentMaintenanceMargin
? totalBalance - BigInt(currentMaintenanceMargin)
: totalBalance
).toString();
details.push({
indent: true,
label: t('Total margin available'),
value: `~${formatValueWithAssetDp(totalMarginAvailable)}`,
symbol: assetSymbol,
labelDescription: TOTAL_MARGIN_AVAILABLE(
formatValueWithAssetDp(generalAccountBalance),
formatValueWithAssetDp(marginAccountBalance),
formatValueWithAssetDp(currentMaintenanceMargin),
assetSymbol
),
});
if (marginAccountBalance) {
const deductionFromCollateral =
BigInt(estimatedTotalInitialMargin) - BigInt(marginAccountBalance);
details.push({
indent: true,
label: t('Deduction from collateral'),
value: `~${formatValueWithAssetDp(
deductionFromCollateral > 0 ? deductionFromCollateral.toString() : '0'
)}`,
symbol: assetSymbol,
labelDescription: DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT(assetSymbol),
});
}
if (balance) {
details.push({
label: t('Projected margin'),
value: `~${formatValueWithAssetDp(estimatedTotalInitialMargin)}`,
value: `~${formatValueWithAssetDp(totalMargin)}`,
symbol: assetSymbol,
labelDescription: EST_TOTAL_MARGIN_TOOLTIP_TEXT,
});
}
details.push({
label: t('Current margin allocation'),
value: `${formatValueWithAssetDp(marginAccountBalance)}`,
value: balance
? `~${formatValueWithAssetDp(balance)}`
: `${formatValueWithAssetDp(balance)}`,
symbol: assetSymbol,
labelDescription: MARGIN_ACCOUNT_TOOLTIP_TEXT,
});
@@ -65,11 +65,5 @@ export const useInitialMargin = (
sellMargin > buyMargin ? sellMargin.toString() : buyMargin.toString();
}
return useMemo(
() => ({
totalMargin,
margin,
}),
[totalMargin, margin]
);
return useMemo(() => ({ totalMargin, margin }), [totalMargin, margin]);
};
@@ -174,7 +174,7 @@ const ApprovalTxFeedback = ({
<>
<p>
{t(
`Your ${selectedAsset?.symbol} approval is being confirmed by the Ethereum network. When this is complete, you can continue your deposit`
`Your ${selectedAsset?.symbol} is being confirmed by the Ethereum network. When this is complete, you can continue your deposit`
)}{' '}
</p>
{txLink && <p>{txLink}</p>}
@@ -61,7 +61,6 @@ beforeEach(() => {
submitDeposit: jest.fn(),
submitFaucet: jest.fn(),
onDisconnect: jest.fn(),
handleAmountChange: jest.fn(),
approveTxId: null,
faucetTxId: null,
isFaucetable: true,
+10 -16
View File
@@ -25,9 +25,11 @@ import {
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useWeb3React } from '@web3-react/core';
import BigNumber from 'bignumber.js';
import type { ButtonHTMLAttributes, ChangeEvent, ReactNode } from 'react';
import { useMemo, useState } from 'react';
import { useWatch, Controller, useForm } from 'react-hook-form';
import type { ButtonHTMLAttributes, ReactNode } from 'react';
import { useState } from 'react';
import { useMemo } from 'react';
import { useWatch } from 'react-hook-form';
import { Controller, useForm } from 'react-hook-form';
import { DepositLimits } from './deposit-limits';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import {
@@ -38,7 +40,6 @@ import {
import type { DepositBalances } from './use-deposit-balances';
import { FaucetNotification } from './faucet-notification';
import { ApproveNotification } from './approve-notification';
import { usePersistentDeposit } from './use-persistent-deposit';
interface FormFields {
asset: string;
@@ -52,7 +53,6 @@ export interface DepositFormProps {
selectedAsset?: Asset;
balances: DepositBalances | null;
onSelectAsset: (assetId: string) => void;
handleAmountChange: (amount: string) => void;
onDisconnect: () => void;
submitApprove: () => void;
approveTxId: number | null;
@@ -71,7 +71,6 @@ export const DepositForm = ({
selectedAsset,
balances,
onSelectAsset,
handleAmountChange,
onDisconnect,
submitApprove,
submitDeposit,
@@ -86,8 +85,6 @@ export const DepositForm = ({
const { pubKey, pubKeys: _pubKeys } = useVegaWallet();
const [approveNotificationIntent, setApproveNotificationIntent] =
useState<Intent>(Intent.Warning);
const [persistedDeposit] = usePersistentDeposit(selectedAsset?.id);
const {
register,
handleSubmit,
@@ -98,8 +95,7 @@ export const DepositForm = ({
} = useForm<FormFields>({
defaultValues: {
to: pubKey ? pubKey : undefined,
asset: selectedAsset?.id,
amount: persistedDeposit.amount,
asset: selectedAsset?.id || '',
},
});
@@ -337,9 +333,6 @@ export const DepositForm = ({
return maxSafe(balances?.balance || new BigNumber(0))(v);
},
},
onChange: (e: ChangeEvent<HTMLInputElement>) => {
handleAmountChange(e.target.value || '');
},
})}
/>
{errors.amount?.message && (
@@ -350,9 +343,10 @@ export const DepositForm = ({
{selectedAsset && balances && (
<UseButton
onClick={() => {
const amount = balances.balance.toFixed(selectedAsset.decimals);
setValue('amount', amount);
handleAmountChange(amount);
setValue(
'amount',
balances.balance.toFixed(selectedAsset.decimals)
);
clearErrors('amount');
}}
>
+2 -14
View File
@@ -5,7 +5,7 @@ import { prepend0x } from '@vegaprotocol/smart-contracts';
import sortBy from 'lodash/sortBy';
import { useSubmitApproval } from './use-submit-approval';
import { useSubmitFaucet } from './use-submit-faucet';
import { useCallback, useState } from 'react';
import { useState } from 'react';
import { useDepositBalances } from './use-deposit-balances';
import { useDepositDialog } from './deposit-dialog';
import type { Asset } from '@vegaprotocol/assets';
@@ -14,7 +14,6 @@ import {
useBridgeContract,
useEthereumConfig,
} from '@vegaprotocol/web3';
import { usePersistentDeposit } from './use-persistent-deposit';
interface DepositManagerProps {
assetId?: string;
@@ -29,9 +28,7 @@ export const DepositManager = ({
}: DepositManagerProps) => {
const createEthTransaction = useEthTransactionStore((state) => state.create);
const { config } = useEthereumConfig();
const [persistentDeposit, savePersistentDeposit] =
usePersistentDeposit(initialAssetId);
const [assetId, setAssetId] = useState(persistentDeposit?.assetId);
const [assetId, setAssetId] = useState(initialAssetId);
const asset = assets.find((a) => a.id === assetId);
const bridgeContract = useBridgeContract();
const closeDepositDialog = useDepositDialog((state) => state.close);
@@ -68,26 +65,17 @@ export const DepositManager = ({
closeDepositDialog();
};
const onAmountChange = useCallback(
(amount: string) => {
savePersistentDeposit({ ...persistentDeposit, amount });
},
[savePersistentDeposit, persistentDeposit]
);
return (
<DepositForm
selectedAsset={asset}
onDisconnect={reset}
onSelectAsset={(id) => {
setAssetId(id);
savePersistentDeposit({ assetId: id });
// When we change asset, also clear the tracked faucet/approve transactions so
// we dont render stale UI
approve.reset();
faucet.reset();
}}
handleAmountChange={onAmountChange}
assets={sortBy(assets, 'name')}
submitApprove={approve.perform}
submitDeposit={submitDeposit}
@@ -1,21 +0,0 @@
import { renderHook, waitFor, act } from '@testing-library/react';
import { usePersistentDeposit } from './use-persistent-deposit';
describe('usePersistenDeposit', () => {
it('should return empty data', () => {
const { result } = renderHook(() => usePersistentDeposit());
expect(result.current).toEqual([{ assetId: '' }, expect.any(Function)]);
});
it('should return empty and properly saved data', async () => {
const aId = 'test';
const retObj = { assetId: 'test', amount: '1.00000' };
const { result } = renderHook(() => usePersistentDeposit(aId));
expect(result.current).toEqual([{ assetId: 'test' }, expect.any(Function)]);
await act(() => {
result.current[1](retObj);
});
await waitFor(() => {
expect(result.current[0]).toEqual(retObj);
});
});
});
@@ -1,42 +0,0 @@
import { useMemo } from 'react';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
const STORAGE_KEY = 'vega_deposit_store';
interface PersistedDeposit {
assetId: string;
amount?: string;
}
type PersistedDepositData = Record<string, PersistedDeposit>;
const usePersistentDepositStore = create<{
deposits: PersistedDepositData;
saveValue: (entry: PersistedDeposit) => void;
lastVisited?: PersistedDeposit;
}>()(
persist(
immer((set) => ({
deposits: {},
saveValue: (entry) =>
set((state) => {
const oldValue = state.deposits[entry.assetId] || null;
state.deposits[entry.assetId] = { ...oldValue, ...entry };
state.lastVisited = { ...oldValue, ...entry };
return state;
}),
})),
{ name: STORAGE_KEY }
)
);
export const usePersistentDeposit = (
assetId?: string
): [PersistedDeposit, (entry: PersistedDeposit) => void] => {
const { deposits, lastVisited, saveValue } = usePersistentDepositStore();
const discoveredData = useMemo(() => {
return deposits[assetId || ''] || lastVisited || { assetId: assetId || '' };
}, [deposits, lastVisited, assetId]);
return [discoveredData, saveValue];
};
+3 -3
View File
@@ -1,5 +1,4 @@
import { MaxUint256 } from '@ethersproject/constants';
import { isAssetTypeERC20 } from '@vegaprotocol/utils';
import { isAssetTypeERC20, removeDecimal } from '@vegaprotocol/utils';
import {
EthTxStatus,
useEthereumConfig,
@@ -38,9 +37,10 @@ export const useSubmitApproval = (
},
perform: () => {
if (!asset || !config) return;
const amount = removeDecimal('1000000', asset.decimals);
const id = createEthTransaction(contract, 'approve', [
config?.collateral_bridge_contract.address,
MaxUint256.toString(),
amount,
]);
setId(id);
},
@@ -140,6 +140,8 @@ describe('Network switcher', () => {
[Networks.STAGNET3]: 'https://stag3.net',
[Networks.DEVNET]: 'https://dev.net',
[Networks.STAGNET1]: 'https://stag1.net',
[Networks.SANDBOX]: 'https://sandbox.net',
[Networks.MIRROR]: 'https://mirror.net',
};
// @ts-ignore Typescript doesn't know about this module being mocked
useEnvironment.mockImplementation(() => ({
@@ -179,6 +181,8 @@ describe('Network switcher', () => {
[Networks.STAGNET3]: 'https://stag3.net',
[Networks.DEVNET]: 'https://dev.net',
[Networks.STAGNET1]: 'https://stag1.net',
[Networks.SANDBOX]: 'https://sandbox.net',
[Networks.MIRROR]: 'https://mirror.net',
};
// @ts-ignore Typescript doesn't know about this module being mocked
useEnvironment.mockImplementation(() => ({
@@ -211,6 +215,8 @@ describe('Network switcher', () => {
[Networks.STAGNET3]: 'https://stag3.net',
[Networks.DEVNET]: 'https://dev.net',
[Networks.STAGNET1]: 'https://stag1.net',
[Networks.SANDBOX]: 'https://sandbox.net',
[Networks.MIRROR]: 'https://mirror.net',
};
// @ts-ignore Typescript doesn't know about this module being mocked
useEnvironment.mockImplementation(() => ({
@@ -17,10 +17,12 @@ export const envNameMapping: Record<Networks, string> = {
[Networks.VALIDATOR_TESTNET]: t('VALIDATOR_TESTNET'),
[Networks.CUSTOM]: t('Custom'),
[Networks.DEVNET]: t('Devnet'),
[Networks.SANDBOX]: t('Sandbox'),
[Networks.STAGNET1]: t('Stagnet'),
[Networks.STAGNET3]: t('Stagnet3'),
[Networks.TESTNET]: t('Fairground testnet'),
[Networks.MAINNET]: t('Mainnet'),
[Networks.MIRROR]: t('Mainnet mirror'),
};
export const envTriggerMapping: Record<Networks, string> = {
@@ -30,6 +32,7 @@ export const envTriggerMapping: Record<Networks, string> = {
export const envDescriptionMapping: Record<Networks, string> = {
[Networks.CUSTOM]: '',
[Networks.SANDBOX]: t('A playground test environment'),
[Networks.VALIDATOR_TESTNET]: t('The validator deployed testnet'),
[Networks.DEVNET]: t('The latest Vega code auto-deployed'),
[Networks.STAGNET1]: t('A release candidate for the staging environment'),
@@ -38,6 +41,9 @@ export const envDescriptionMapping: Record<Networks, string> = {
'Public testnet run by the Vega team, often used for incentives'
),
[Networks.MAINNET]: t('The vega mainnet'),
[Networks.MIRROR]: t(
'A mirror of the mainnet environment running on an Ethereum test network'
),
};
const standardNetworkKeys = [Networks.MAINNET, Networks.TESTNET];
+2 -2
View File
@@ -3,7 +3,7 @@ import { useCallback } from 'react';
import { Networks } from '../types';
import { useEnvironment } from './use-environment';
type Net = Exclude<Networks, 'CUSTOM'>;
type Net = Exclude<Networks, 'CUSTOM' | 'SANDBOX'>;
export enum DApp {
Explorer = 'Explorer',
Console = 'Console',
@@ -60,7 +60,7 @@ export const useLinks = (dapp: DApp, network?: Net) => {
};
let net = network || VEGA_ENV;
if (net === Networks.CUSTOM) {
if (net === Networks.CUSTOM || net === Networks.SANDBOX) {
net = Networks.TESTNET;
}
+2
View File
@@ -5,11 +5,13 @@ import type { envSchema } from './utils/validate-environment';
export enum Networks {
VALIDATOR_TESTNET = 'VALIDATOR_TESTNET',
CUSTOM = 'CUSTOM',
SANDBOX = 'SANDBOX',
TESTNET = 'TESTNET',
STAGNET1 = 'STAGNET1',
STAGNET3 = 'STAGNET3',
DEVNET = 'DEVNET',
MAINNET = 'MAINNET',
MIRROR = 'MIRROR',
}
export type Environment = z.infer<typeof envSchema>;
export type Configuration = z.infer<typeof tomlConfigSchema>;
@@ -3,11 +3,13 @@ import z from 'zod';
export enum Networks {
VALIDATOR_TESTNET = 'VALIDATOR_TESTNET',
CUSTOM = 'CUSTOM',
SANDBOX = 'SANDBOX',
TESTNET = 'TESTNET',
STAGNET1 = 'STAGNET1',
STAGNET3 = 'STAGNET3',
DEVNET = 'DEVNET',
MAINNET = 'MAINNET',
MIRROR = 'MIRROR',
}
const schemaObject = {
@@ -103,3 +103,13 @@ query LiquidityProviderFeeShare($marketId: ID!) {
}
}
}
subscription LiquidityProviderFeeShareUpdate($marketId: ID!) {
marketsData(marketIds: [$marketId]) {
liquidityProviderFeeShare {
partyId
equityLikeShare
averageEntryValuation
}
}
}
+42 -1
View File
@@ -36,6 +36,13 @@ export type LiquidityProviderFeeShareQueryVariables = Types.Exact<{
export type LiquidityProviderFeeShareQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, data?: { __typename?: 'MarketData', market: { __typename?: 'Market', id: string }, liquidityProviderFeeShare?: Array<{ __typename?: 'LiquidityProviderFeeShare', equityLikeShare: string, averageEntryValuation: string, party: { __typename?: 'Party', id: string } }> | null } | null } | null };
export type LiquidityProviderFeeShareUpdateSubscriptionVariables = Types.Exact<{
marketId: Types.Scalars['ID'];
}>;
export type LiquidityProviderFeeShareUpdateSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', liquidityProviderFeeShare?: Array<{ __typename?: 'ObservableLiquidityProviderFeeShare', partyId: string, equityLikeShare: string, averageEntryValuation: string }> | null }> };
export const LiquidityProvisionFieldsFragmentDoc = gql`
fragment LiquidityProvisionFields on LiquidityProvision {
party {
@@ -249,4 +256,38 @@ export function useLiquidityProviderFeeShareLazyQuery(baseOptions?: Apollo.LazyQ
}
export type LiquidityProviderFeeShareQueryHookResult = ReturnType<typeof useLiquidityProviderFeeShareQuery>;
export type LiquidityProviderFeeShareLazyQueryHookResult = ReturnType<typeof useLiquidityProviderFeeShareLazyQuery>;
export type LiquidityProviderFeeShareQueryResult = Apollo.QueryResult<LiquidityProviderFeeShareQuery, LiquidityProviderFeeShareQueryVariables>;
export type LiquidityProviderFeeShareQueryResult = Apollo.QueryResult<LiquidityProviderFeeShareQuery, LiquidityProviderFeeShareQueryVariables>;
export const LiquidityProviderFeeShareUpdateDocument = gql`
subscription LiquidityProviderFeeShareUpdate($marketId: ID!) {
marketsData(marketIds: [$marketId]) {
liquidityProviderFeeShare {
partyId
equityLikeShare
averageEntryValuation
}
}
}
`;
/**
* __useLiquidityProviderFeeShareUpdateSubscription__
*
* To run a query within a React component, call `useLiquidityProviderFeeShareUpdateSubscription` and pass it any options that fit your needs.
* When your component renders, `useLiquidityProviderFeeShareUpdateSubscription` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useLiquidityProviderFeeShareUpdateSubscription({
* variables: {
* marketId: // value for 'marketId'
* },
* });
*/
export function useLiquidityProviderFeeShareUpdateSubscription(baseOptions: Apollo.SubscriptionHookOptions<LiquidityProviderFeeShareUpdateSubscription, LiquidityProviderFeeShareUpdateSubscriptionVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useSubscription<LiquidityProviderFeeShareUpdateSubscription, LiquidityProviderFeeShareUpdateSubscriptionVariables>(LiquidityProviderFeeShareUpdateDocument, options);
}
export type LiquidityProviderFeeShareUpdateSubscriptionHookResult = ReturnType<typeof useLiquidityProviderFeeShareUpdateSubscription>;
export type LiquidityProviderFeeShareUpdateSubscriptionResult = Apollo.SubscriptionResult<LiquidityProviderFeeShareUpdateSubscription>;
@@ -6,6 +6,7 @@ import produce from 'immer';
import {
LiquidityProviderFeeShareDocument,
LiquidityProviderFeeShareUpdateDocument,
LiquidityProvisionsDocument,
LiquidityProvisionsUpdateDocument,
MarketLpDocument,
@@ -17,6 +18,7 @@ import type {
LiquidityProviderFeeShareFieldsFragment,
LiquidityProviderFeeShareQuery,
LiquidityProviderFeeShareQueryVariables,
LiquidityProviderFeeShareUpdateSubscription,
LiquidityProvisionFieldsFragment,
LiquidityProvisionsQuery,
LiquidityProvisionsQueryVariables,
@@ -113,94 +115,73 @@ export const marketLiquidityDataProvider = makeDataProvider<
export const liquidityFeeShareDataProvider = makeDataProvider<
LiquidityProviderFeeShareQuery,
LiquidityProviderFeeShareFieldsFragment[],
never,
never,
LiquidityProviderFeeShareUpdateSubscription,
LiquidityProviderFeeShareUpdateSubscription['marketsData'][0]['liquidityProviderFeeShare'],
LiquidityProviderFeeShareQueryVariables
>({
query: LiquidityProviderFeeShareDocument,
subscriptionQuery: LiquidityProviderFeeShareUpdateDocument,
update: (
data: LiquidityProviderFeeShareFieldsFragment[] | null,
deltas: LiquidityProviderFeeShareUpdateSubscription['marketsData'][0]['liquidityProviderFeeShare']
) => {
return produce(data || [], (draft) => {
deltas?.forEach((delta) => {
const id = delta.partyId;
const index = draft.findIndex((a) => a.party.id === id);
if (index !== -1) {
draft[index].equityLikeShare = delta.equityLikeShare;
draft[index].averageEntryValuation = delta.averageEntryValuation;
} else {
draft.unshift({
equityLikeShare: delta.equityLikeShare,
averageEntryValuation: delta.averageEntryValuation,
party: {
id: delta.partyId,
},
// TODO add accounts connection to the subscription
});
}
});
});
},
getData: (data) => {
return data?.market?.data?.liquidityProviderFeeShare || [];
},
getDelta: (subscriptionData: LiquidityProviderFeeShareUpdateSubscription) => {
return subscriptionData.marketsData[0].liquidityProviderFeeShare;
},
});
export type Filter = { partyId?: string; active?: boolean };
export const lpAggregatedDataProvider = makeDerivedDataProvider<
LiquidityProvisionData[],
ReturnType<typeof getLiquidityProvision>,
never,
MarketLpQueryVariables & { filter?: Filter }
MarketLpQueryVariables
>(
[
(callback, client, variables) =>
liquidityProvisionsDataProvider(callback, client, {
marketId: variables.marketId,
}),
(callback, client, variables) =>
marketLiquidityDataProvider(callback, client, {
marketId: variables.marketId,
}),
(callback, client, variables) =>
liquidityFeeShareDataProvider(callback, client, {
marketId: variables.marketId,
}),
liquidityProvisionsDataProvider,
marketLiquidityDataProvider,
liquidityFeeShareDataProvider,
],
(
[liquidityProvisions, marketLiquidity, liquidityFeeShare],
{ filter }
): LiquidityProvisionData[] => {
([
liquidityProvisions,
marketLiquidity,
liquidityFeeShare,
]): LiquidityProvisionData[] => {
return getLiquidityProvision(
liquidityProvisions,
marketLiquidity,
liquidityFeeShare,
filter
liquidityFeeShare
);
}
);
export const matchFilter = (
filter: Filter,
lp: LiquidityProvisionFieldsFragment
) => {
if (filter.partyId && lp.party.id !== filter.partyId) {
return false;
}
if (
filter.active === true &&
lp.status !== Schema.LiquidityProvisionStatus.STATUS_ACTIVE
) {
return false;
}
if (
filter.active === false &&
lp.status === Schema.LiquidityProvisionStatus.STATUS_ACTIVE
) {
return false;
}
return true;
};
export const getLiquidityProvision = (
liquidityProvisions: LiquidityProvisionFieldsFragment[],
marketLiquidity: MarketLpQuery,
liquidityFeeShare: LiquidityProviderFeeShareFieldsFragment[],
filter?: Filter
liquidityFeeShare: LiquidityProviderFeeShareFieldsFragment[]
): LiquidityProvisionData[] => {
return liquidityProvisions
.filter((lp) => {
if (
![
Schema.LiquidityProvisionStatus.STATUS_ACTIVE,
Schema.LiquidityProvisionStatus.STATUS_UNDEPLOYED,
Schema.LiquidityProvisionStatus.STATUS_PENDING,
].includes(lp.status)
) {
return false;
}
if (filter && !matchFilter(filter, lp)) {
return false;
}
return true;
})
.map((lp) => {
const market = marketLiquidity?.market;
const feeShare = liquidityFeeShare.find(
@@ -229,7 +210,14 @@ export const getLiquidityProvision = (
.decimals,
balance,
};
});
})
.filter((e) =>
[
Schema.LiquidityProvisionStatus.STATUS_ACTIVE,
Schema.LiquidityProvisionStatus.STATUS_UNDEPLOYED,
Schema.LiquidityProvisionStatus.STATUS_PENDING,
].includes(e.status)
);
};
export interface LiquidityProvisionData
@@ -14,8 +14,6 @@ fragment OrderFields on Order {
expiresAt
createdAt
updatedAt
postOnly
reduceOnly
liquidityProvision {
__typename
}
@@ -32,16 +30,12 @@ query OrderById($orderId: ID!) {
query Orders(
$partyId: ID!
$marketIds: [ID!]
$pagination: Pagination
$filter: OrderFilter
$filter: OrderByMarketIdsFilter
) {
party(id: $partyId) {
id
ordersConnection(
pagination: $pagination
filter: { order: $filter, marketIds: $marketIds }
) {
ordersConnection(pagination: $pagination, filter: $filter) {
edges {
node {
...OrderFields
@@ -78,8 +72,8 @@ fragment OrderUpdateFields on OrderUpdate {
}
}
subscription OrdersUpdate($partyId: ID!, $marketIds: [ID!]) {
orders(filter: { partyIds: [$partyId], marketIds: $marketIds }) {
subscription OrdersUpdate($partyId: ID!) {
orders(filter: { partyIds: [$partyId] }) {
...OrderUpdateFields
}
}
@@ -3,30 +3,28 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type OrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, postOnly?: boolean | null, reduceOnly?: boolean | null, market: { __typename?: 'Market', id: string }, liquidityProvision?: { __typename: 'LiquidityProvision' } | null, peggedOrder?: { __typename: 'PeggedOrder' } | null };
export type OrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, market: { __typename?: 'Market', id: string }, liquidityProvision?: { __typename: 'LiquidityProvision' } | null, peggedOrder?: { __typename: 'PeggedOrder' } | null };
export type OrderByIdQueryVariables = Types.Exact<{
orderId: Types.Scalars['ID'];
}>;
export type OrderByIdQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, postOnly?: boolean | null, reduceOnly?: boolean | null, market: { __typename?: 'Market', id: string }, liquidityProvision?: { __typename: 'LiquidityProvision' } | null, peggedOrder?: { __typename: 'PeggedOrder' } | null } };
export type OrderByIdQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, market: { __typename?: 'Market', id: string }, liquidityProvision?: { __typename: 'LiquidityProvision' } | null, peggedOrder?: { __typename: 'PeggedOrder' } | null } };
export type OrdersQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
marketIds?: Types.InputMaybe<Array<Types.Scalars['ID']> | Types.Scalars['ID']>;
pagination?: Types.InputMaybe<Types.Pagination>;
filter?: Types.InputMaybe<Types.OrderFilter>;
filter?: Types.InputMaybe<Types.OrderByMarketIdsFilter>;
}>;
export type OrdersQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, ordersConnection?: { __typename?: 'OrderConnection', edges?: Array<{ __typename?: 'OrderEdge', cursor?: string | null, node: { __typename?: 'Order', id: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, postOnly?: boolean | null, reduceOnly?: boolean | null, market: { __typename?: 'Market', id: string }, liquidityProvision?: { __typename: 'LiquidityProvision' } | null, peggedOrder?: { __typename: 'PeggedOrder' } | null } }> | null, pageInfo?: { __typename?: 'PageInfo', startCursor: string, endCursor: string, hasNextPage: boolean, hasPreviousPage: boolean } | null } | null } | null };
export type OrdersQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, ordersConnection?: { __typename?: 'OrderConnection', edges?: Array<{ __typename?: 'OrderEdge', cursor?: string | null, node: { __typename?: 'Order', id: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, market: { __typename?: 'Market', id: string }, liquidityProvision?: { __typename: 'LiquidityProvision' } | null, peggedOrder?: { __typename: 'PeggedOrder' } | null } }> | null, pageInfo?: { __typename?: 'PageInfo', startCursor: string, endCursor: string, hasNextPage: boolean, hasPreviousPage: boolean } | null } | null } | null };
export type OrderUpdateFieldsFragment = { __typename?: 'OrderUpdate', id: string, marketId: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, liquidityProvisionId?: string | null, peggedOrder?: { __typename: 'PeggedOrder' } | null };
export type OrdersUpdateSubscriptionVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
marketIds?: Types.InputMaybe<Array<Types.Scalars['ID']> | Types.Scalars['ID']>;
}>;
@@ -49,8 +47,6 @@ export const OrderFieldsFragmentDoc = gql`
expiresAt
createdAt
updatedAt
postOnly
reduceOnly
liquidityProvision {
__typename
}
@@ -116,13 +112,10 @@ export type OrderByIdQueryHookResult = ReturnType<typeof useOrderByIdQuery>;
export type OrderByIdLazyQueryHookResult = ReturnType<typeof useOrderByIdLazyQuery>;
export type OrderByIdQueryResult = Apollo.QueryResult<OrderByIdQuery, OrderByIdQueryVariables>;
export const OrdersDocument = gql`
query Orders($partyId: ID!, $marketIds: [ID!], $pagination: Pagination, $filter: OrderFilter) {
query Orders($partyId: ID!, $pagination: Pagination, $filter: OrderByMarketIdsFilter) {
party(id: $partyId) {
id
ordersConnection(
pagination: $pagination
filter: {order: $filter, marketIds: $marketIds}
) {
ordersConnection(pagination: $pagination, filter: $filter) {
edges {
node {
...OrderFields
@@ -153,7 +146,6 @@ export const OrdersDocument = gql`
* const { data, loading, error } = useOrdersQuery({
* variables: {
* partyId: // value for 'partyId'
* marketIds: // value for 'marketIds'
* pagination: // value for 'pagination'
* filter: // value for 'filter'
* },
@@ -171,8 +163,8 @@ export type OrdersQueryHookResult = ReturnType<typeof useOrdersQuery>;
export type OrdersLazyQueryHookResult = ReturnType<typeof useOrdersLazyQuery>;
export type OrdersQueryResult = Apollo.QueryResult<OrdersQuery, OrdersQueryVariables>;
export const OrdersUpdateDocument = gql`
subscription OrdersUpdate($partyId: ID!, $marketIds: [ID!]) {
orders(filter: {partyIds: [$partyId], marketIds: $marketIds}) {
subscription OrdersUpdate($partyId: ID!) {
orders(filter: {partyIds: [$partyId]}) {
...OrderUpdateFields
}
}
@@ -191,7 +183,6 @@ export const OrdersUpdateDocument = gql`
* const { data, loading, error } = useOrdersUpdateSubscription({
* variables: {
* partyId: // value for 'partyId'
* marketIds: // value for 'marketIds'
* },
* });
*/
@@ -112,7 +112,9 @@ describe('order data provider', () => {
const updatedData = update(data, delta, () => null, {
partyId: '0x123',
filter: {
dateRange: { end: new Date('2022-02-01').toISOString() },
order: {
dateRange: { end: new Date('2022-02-01').toISOString() },
},
},
});
expect(
@@ -35,40 +35,45 @@ const orderMatchFilters = (
return true;
}
if (
variables?.filter?.status &&
!(order.status && variables.filter.status.includes(order.status))
variables?.filter?.order?.status &&
!(order.status && variables.filter.order.status.includes(order.status))
) {
return false;
}
if (
variables?.filter?.types &&
!(order.type && variables.filter.types.includes(order.type))
variables?.filter?.order?.types &&
!(order.type && variables.filter.order.types.includes(order.type))
) {
return false;
}
if (
variables?.filter?.timeInForce &&
!variables.filter.timeInForce.includes(order.timeInForce)
variables?.filter?.order?.timeInForce &&
!variables.filter.order.timeInForce.includes(order.timeInForce)
) {
return false;
}
if (variables?.filter?.excludeLiquidity && order.liquidityProvisionId) {
if (
variables?.filter?.order?.excludeLiquidity &&
order.liquidityProvisionId
) {
return false;
}
if (
variables?.filter?.dateRange?.start &&
variables?.filter?.order?.dateRange?.start &&
!(
(order.updatedAt || order.createdAt) &&
variables.filter.dateRange.start < (order.updatedAt || order.createdAt)
variables.filter.order.dateRange.start <
(order.updatedAt || order.createdAt)
)
) {
return false;
}
if (
variables?.filter?.dateRange?.end &&
variables?.filter?.order?.dateRange?.end &&
!(
(order.updatedAt || order.createdAt) &&
variables.filter.dateRange.end > (order.updatedAt || order.createdAt)
variables.filter.order.dateRange.end >
(order.updatedAt || order.createdAt)
)
) {
return false;
@@ -238,17 +243,18 @@ export const hasActiveOrderProvider = makeDerivedDataProvider<
{ partyId: string; marketId?: string }
>(
[
(callback, client, { partyId, marketId }) =>
(callback, client, variables) =>
hasActiveOrderProviderInternal(callback, client, {
marketIds: marketId ? [marketId] : undefined,
filter: {
status: [OrderStatus.STATUS_ACTIVE],
excludeLiquidity: true,
order: {
status: [OrderStatus.STATUS_ACTIVE],
excludeLiquidity: true,
},
},
pagination: {
first: 1,
},
partyId,
...variables,
} as OrdersQueryVariables),
],
(parts) => parts[0]
@@ -72,10 +72,12 @@ export const useOrderListData = ({
const allVars: OrdersQueryVariables & OrdersUpdateSubscriptionVariables = {
partyId,
filter: {
dateRange: filter?.updatedAt?.value,
status: filter?.status?.value,
timeInForce: filter?.timeInForce?.value,
types: filter?.type?.value,
order: {
dateRange: filter?.updatedAt?.value,
status: filter?.status?.value,
timeInForce: filter?.timeInForce?.value,
types: filter?.type?.value,
},
},
pagination: {
first: 1000,
@@ -129,9 +129,8 @@ export const OrderListTable = memo(
}: VegaValueFormatterParams<Order, 'status'>) => {
if (data?.rejectionReason && value) {
return `${Schema.OrderStatusMapping[value]}: ${
(data?.rejectionReason &&
Schema.OrderRejectionReasonMapping[data.rejectionReason]) ||
data?.rejectionReason
data?.rejectionReason &&
Schema.OrderRejectionReasonMapping[data.rejectionReason]
}`;
}
return value ? Schema.OrderStatusMapping[value] : '';
@@ -219,14 +218,7 @@ export const OrderListTable = memo(
return `${Schema.OrderTimeInForceMapping[value]}: ${expiry}`;
}
const tifLabel = value
? Schema.OrderTimeInForceMapping[value]
: '';
const label = `${tifLabel}${
data?.postOnly ? t('. Post Only') : ''
}${data?.reduceOnly ? t('. Reduce only') : ''}`;
return label;
return value ? Schema.OrderTimeInForceMapping[value] : '';
}}
minWidth={150}
/>
@@ -53,12 +53,14 @@ export const useActiveOrdersVolumeAndMargin = (
update,
variables: {
partyId: partyId || '',
marketIds: [marketId],
filter: {
status: [
OrderStatus.STATUS_ACTIVE,
OrderStatus.STATUS_PARTIALLY_FILLED,
],
marketIds: [marketId],
order: {
status: [
OrderStatus.STATUS_ACTIVE,
OrderStatus.STATUS_PARTIALLY_FILLED,
],
},
},
},
skip: !partyId,
+1
View File
@@ -4,6 +4,7 @@ export * from './lib/positions-data-providers';
export * from './lib/margin-data-provider';
export * from './lib/margin-calculator';
export * from './lib/positions-table';
export * from './lib/use-close-position';
export * from './lib/use-market-margin';
export * from './lib/use-market-position-open-volume';
export * from './lib/use-open-volume';
@@ -0,0 +1,109 @@
import { useEnvironment } from '@vegaprotocol/environment';
import type { OrderFieldsFragment } from '@vegaprotocol/orders';
import { truncateByChars } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import * as Schema from '@vegaprotocol/types';
import { Link } from '@vegaprotocol/ui-toolkit';
import type { TransactionResult, VegaTxState } from '@vegaprotocol/wallet';
import type { ClosingOrder as IClosingOrder } from '../use-close-position';
import { useRequestClosePositionData } from '../use-request-close-position-data';
import { ClosingOrder } from './shared';
interface CompleteProps {
partyId: string;
transaction: VegaTxState;
transactionResult?: TransactionResult;
closingOrder?: IClosingOrder;
closingOrderResult?: OrderFieldsFragment;
}
export const Complete = ({
partyId,
transaction,
transactionResult,
closingOrder,
closingOrderResult,
}: CompleteProps) => {
const { VEGA_EXPLORER_URL } = useEnvironment();
if (!transactionResult || !closingOrderResult) return null;
return (
<>
{closingOrderResult.status === Schema.OrderStatus.STATUS_FILLED &&
transactionResult.status ? (
<Success partyId={partyId} order={closingOrder} />
) : (
<Error
transactionResult={transactionResult}
closingOrderResult={closingOrderResult}
/>
)}
{transaction.txHash && (
<>
<p className="font-semibold mt-4">{t('Transaction')}</p>
<p>
<Link
href={`${VEGA_EXPLORER_URL}/txs/${transaction.txHash}`}
target="_blank"
>
{truncateByChars(transaction.txHash)}
</Link>
</p>
</>
)}
</>
);
};
const Success = ({
partyId,
order,
}: {
partyId: string;
order?: IClosingOrder;
}) => {
const { market, marketData, orders } = useRequestClosePositionData(
order?.marketId,
partyId
);
if (!market || !marketData || !orders) {
return <div>{t('Loading...')}</div>;
}
if (!order) {
return (
<div className="text-vega-pink">{t('Could retrieve closing order')}</div>
);
}
return (
<>
<h2 className="font-bold">{t('Position closed')}</h2>
<ClosingOrder order={order} market={market} marketData={marketData} />
</>
);
};
const Error = ({
transactionResult,
closingOrderResult,
}: {
transactionResult: TransactionResult;
closingOrderResult: OrderFieldsFragment;
}) => {
const reason =
closingOrderResult.rejectionReason &&
Schema.OrderRejectionReasonMapping[closingOrderResult.rejectionReason];
return (
<div className="text-vega-pink">
{reason ? (
<p>{reason}</p>
) : (
<p>
{t('Transaction failed')}: {transactionResult.error}
</p>
)}
</div>
);
};
@@ -0,0 +1,102 @@
import { render, screen, within } from '@testing-library/react';
import * as Schema from '@vegaprotocol/types';
import * as dataHook from '../use-request-close-position-data';
import { Requested } from './requested';
jest.mock('./use-request-close-position-data');
describe('Close position dialog - Request', () => {
const props = {
partyId: 'party-id',
order: {
marketId: 'market-id',
type: Schema.OrderType.TYPE_MARKET as const,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK as const,
side: Schema.Side.SIDE_BUY,
size: '10',
},
};
it('loading state', async () => {
jest.spyOn(dataHook, 'useRequestClosePositionData').mockReturnValue({
loading: false,
market: null,
marketData: null,
orders: [],
});
render(<Requested {...props} />);
expect(screen.getByText('Loading...')).toBeInTheDocument();
});
it('renders message if no closing order found', async () => {
const orders = [
{
size: '200',
price: '999',
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
},
{
size: '300',
price: '888',
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
},
];
jest.spyOn(dataHook, 'useRequestClosePositionData').mockReturnValue({
market: {
decimalPlaces: 2,
positionDecimalPlaces: 2,
tradableInstrument: {
instrument: {
name: 'test market',
product: {
// @ts-ignore avoiding having to add every property on the type
settlementAsset: {
symbol: 'SYM',
},
},
},
},
},
// @ts-ignore avoid all fields
marketData: {
markPrice: '100',
},
// @ts-ignore avoid all fields
orders,
});
render(<Requested {...props} />);
// closing order
const closingOrderHeader = screen.getByText('Position to be closed');
const closingOrderTable = within(
closingOrderHeader.nextElementSibling?.querySelector(
'tbody'
) as HTMLElement
);
const closingOrderRow = closingOrderTable.getAllByRole('row');
expect(closingOrderRow[0].children[0]).toHaveTextContent('test market');
expect(closingOrderRow[0].children[1]).toHaveTextContent('+0.1');
expect(closingOrderRow[0].children[2]).toHaveTextContent('~1.00 SYM');
// orders
const ordersHeading = screen.getByText('Orders to be closed');
const ordersTable = within(
ordersHeading.nextElementSibling?.querySelector('tbody') as HTMLElement
);
const orderRows = ordersTable.getAllByRole('row');
expect(orderRows).toHaveLength(orders.length);
expect(orderRows[0].children[0]).toHaveTextContent('+2');
expect(orderRows[0].children[1]).toHaveTextContent('9.99 SYM');
expect(orderRows[0].children[2]).toHaveTextContent(
"Good 'til Cancelled (GTC)"
);
expect(orderRows[1].children[0]).toHaveTextContent('-3');
expect(orderRows[1].children[1]).toHaveTextContent('8.88 SYM');
expect(orderRows[1].children[2]).toHaveTextContent(
"Good 'til Cancelled (GTC)"
);
});
});
@@ -0,0 +1,37 @@
import { t } from '@vegaprotocol/i18n';
import type { ClosingOrder as IClosingOrder } from '../use-close-position';
import { useRequestClosePositionData } from '../use-request-close-position-data';
import { ActiveOrders, ClosingOrder } from './shared';
export const Requested = ({
order,
partyId,
}: {
order?: IClosingOrder;
partyId: string;
}) => {
const { market, marketData, orders, loading } = useRequestClosePositionData(
order?.marketId,
partyId
);
if (loading || !market || !marketData || !orders) {
return <div>{t('Loading...')}</div>;
}
if (!order) {
return (
<div className="text-vega-pink">
{t('Could not create closing order')}
</div>
);
}
return (
<>
<h2 className="font-bold">{t('Position to be closed')}</h2>
<ClosingOrder order={order} market={market} marketData={marketData} />
<ActiveOrders market={market} orders={orders} />
</>
);
};
@@ -0,0 +1,114 @@
import type { MarketData, Market } from '@vegaprotocol/market-list';
import type { Order } from '@vegaprotocol/orders';
import { timeInForceLabel } from '@vegaprotocol/orders';
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { Size } from '@vegaprotocol/react-helpers';
import type { ReactNode } from 'react';
import type { ClosingOrder as IClosingOrder } from '../use-close-position';
export const ClosingOrder = ({
order,
market,
marketData,
}: {
order: IClosingOrder;
market: Market;
marketData: MarketData;
}) => {
const asset = market.tradableInstrument.instrument.product.settlementAsset;
const estimatedPrice =
marketData && market
? addDecimalsFormatNumber(marketData.markPrice, market.decimalPlaces)
: '-';
const size = market ? (
<Size
value={order.size}
side={order.side}
positionDecimalPlaces={market.positionDecimalPlaces}
/>
) : (
'-'
);
return (
<BasicTable
headers={[t('Market'), t('Amount'), t('Est price')]}
rows={[
[
market.tradableInstrument.instrument.name,
size,
`~${estimatedPrice} ${asset?.symbol}`,
],
]}
/>
);
};
export const ActiveOrders = ({
market,
orders,
}: {
market: Market;
orders: Order[];
}) => {
const asset = market.tradableInstrument.instrument.product.settlementAsset;
if (!orders.length) {
return null;
}
return (
<div className="mt-4">
<h2 className="font-bold">{t('Orders to be closed')}</h2>
<BasicTable
headers={[t('Amount'), t('Target price'), t('Time in force')]}
rows={orders.map((o) => {
return [
<Size
value={o.size}
side={o.side}
positionDecimalPlaces={market.positionDecimalPlaces}
/>,
`${addDecimalsFormatNumber(o.price, market.decimalPlaces)} ${
asset.symbol
}`,
timeInForceLabel(o.timeInForce),
];
})}
/>
</div>
);
};
interface BasicTableProps {
headers: ReactNode[];
rows: ReactNode[][];
}
const BasicTable = ({ headers, rows }: BasicTableProps) => {
return (
<table className="w-full">
<thead>
<tr>
{headers.map((h, i) => (
<th key={i} className="text-left font-medium">
{h}
</th>
))}
</tr>
</thead>
<tbody>
{rows.map((cells, i) => (
<tr key={i}>
{cells.map((c, i) => (
<td key={i} className="align-top">
{c}
</td>
))}
</tr>
))}
</tbody>
</table>
);
};
@@ -349,15 +349,16 @@ export const volumeAndMarginProvider = makeDerivedDataProvider<
PositionsQueryVariables & MarketDataQueryVariables
>(
[
(callback, client, { partyId, marketId }) =>
(callback, client, variables) =>
ordersProvider(callback, client, {
partyId,
marketIds: [marketId],
...variables,
filter: {
status: [
OrderStatus.STATUS_ACTIVE,
OrderStatus.STATUS_PARTIALLY_FILLED,
],
order: {
status: [
OrderStatus.STATUS_ACTIVE,
OrderStatus.STATUS_PARTIALLY_FILLED,
],
},
},
}),
(callback, client, variables) =>
+8 -5
View File
@@ -1,7 +1,8 @@
import { useCallback, useRef, useState } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import type { Position } from '../';
import { usePositionsData, PositionsTable } from '../';
import type { FilterChangedEvent } from 'ag-grid-community';
import type { AgGridReact } from 'ag-grid-react';
import * as Schema from '@vegaprotocol/types';
import { useVegaTransactionStore } from '@vegaprotocol/wallet';
@@ -22,8 +23,8 @@ export const PositionsManager = ({
noBottomPlaceholder,
}: PositionsManagerProps) => {
const gridRef = useRef<AgGridReact | null>(null);
const [dataCount, setDataCount] = useState(0);
const { data, error, loading, reload } = usePositionsData(partyId, gridRef);
const [dataCount, setDataCount] = useState(data?.length ?? 0);
const create = useVegaTransactionStore((store) => store.create);
const onClose = ({
marketId,
@@ -66,7 +67,10 @@ export const PositionsManager = ({
setId,
disabled: noBottomPlaceholder,
});
const updateRowCount = useCallback(() => {
useEffect(() => {
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
}, [data]);
const onFilterChanged = useCallback((event: FilterChangedEvent) => {
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
}, []);
return (
@@ -79,8 +83,7 @@ export const PositionsManager = ({
suppressLoadingOverlay
suppressNoRowsOverlay
isReadOnly={isReadOnly}
onFilterChanged={updateRowCount}
onRowDataUpdated={updateRowCount}
onFilterChanged={onFilterChanged}
{...bottomPlaceholderProps}
/>
<div className="pointer-events-none absolute inset-0">
@@ -0,0 +1,211 @@
import type { ReactNode } from 'react';
import type { MockedResponse } from '@apollo/client/testing';
import { MockedProvider } from '@apollo/client/testing';
import { renderHook, waitFor } from '@testing-library/react';
import * as Types from '@vegaprotocol/types';
import { useClosePosition } from './use-close-position';
import { VegaTxStatus, VegaWalletContext } from '@vegaprotocol/wallet';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { initialState } from '@vegaprotocol/wallet';
import type { TransactionEventSubscription } from '@vegaprotocol/wallet';
import { TransactionEventDocument } from '@vegaprotocol/wallet';
import { act } from 'react-dom/test-utils';
import type { OrderSubSubscription } from '@vegaprotocol/orders';
import { OrderSubDocument } from '@vegaprotocol/orders';
const pubKey = 'test-pubkey';
const defaultWalletContext = {
pubKey,
pubKeys: [{ publicKey: pubKey, name: 'test pubkey' }],
isReadOnly: false,
sendTx: jest.fn().mockReturnValue(Promise.resolve(null)),
connect: jest.fn(),
disconnect: jest.fn(),
selectPubKey: jest.fn(),
connector: null,
};
const txResult = {
__typename: 'TransactionResult',
partyId: pubKey,
hash: '0x123',
status: true,
error: null,
};
function setup(context?: Partial<VegaWalletContextShape>) {
const mockTransactionResult: MockedResponse<TransactionEventSubscription> = {
request: {
query: TransactionEventDocument,
variables: {
partyId: context?.pubKey || '',
},
},
result: {
data: {
busEvents: [
{
type: Types.BusEventType.TransactionResult,
event: txResult,
__typename: 'BusEvent',
},
] as TransactionEventSubscription['busEvents'],
},
},
};
const mockOrderResult: MockedResponse<OrderSubSubscription> = {
request: {
query: OrderSubDocument,
variables: {
partyId: context?.pubKey || '',
},
},
result: {
data: {
orders: [
{
type: Types.OrderType.TYPE_LIMIT,
id: '2fca514cebf9f465ae31ecb4c5721e3a6f5f260425ded887ca50ba15b81a5d50',
status: Types.OrderStatus.STATUS_ACTIVE,
rejectionReason: null,
createdAt: '2022-07-05T14:25:47.815283706Z',
expiresAt: '2022-07-05T14:25:47.815283706Z',
size: '10',
price: '300000',
timeInForce: Types.OrderTimeInForce.TIME_IN_FORCE_GTC,
side: Types.Side.SIDE_BUY,
marketId: 'market-id',
__typename: 'OrderUpdate',
},
],
},
},
};
const wrapper = ({ children }: { children: ReactNode }) => (
<MockedProvider mocks={[mockTransactionResult, mockOrderResult]}>
<VegaWalletContext.Provider
value={{ ...defaultWalletContext, ...context }}
>
{children}
</VegaWalletContext.Provider>
</MockedProvider>
);
return renderHook(() => useClosePosition(), { wrapper });
}
describe('useClosePosition', () => {
const txResponse = {
signature:
'cfe592d169f87d0671dd447751036d0dddc165b9c4b65e5a5060e2bbadd1aa726d4cbe9d3c3b327bcb0bff4f83999592619a2493f9bbd251fae99ce7ce766909',
transactionHash: '0x123',
};
it('doesnt send the tx if there is no open volume', () => {
const mockSend = jest.fn();
const { result } = setup({ sendTx: mockSend });
expect(result.current).toEqual({
submit: expect.any(Function),
transaction: initialState,
Dialog: expect.any(Function),
});
result.current.submit({ marketId: 'test-market', openVolume: '0' });
expect(mockSend).not.toBeCalled();
expect(result.current.transaction.status).toEqual(VegaTxStatus.Default);
});
it('doesnt send the tx if there is no pubkey', () => {
const mockSend = jest.fn();
const { result } = setup({ sendTx: mockSend, pubKey: null });
result.current.submit({ marketId: 'test-market', openVolume: '1000' });
expect(mockSend).not.toBeCalled();
expect(result.current.transaction.status).toEqual(VegaTxStatus.Default);
});
it('closes long positions', async () => {
const marketId = 'test-market';
const openVolume = '1000';
const mockSend = jest.fn().mockResolvedValue(txResponse);
const { result } = setup({ sendTx: mockSend, pubKey });
act(() => {
result.current.submit({ marketId, openVolume });
});
expect(mockSend).toBeCalledWith(defaultWalletContext.pubKey, {
batchMarketInstructions: {
cancellations: [
{
marketId,
orderId: '',
},
],
submissions: [
{
marketId,
type: Types.OrderType.TYPE_MARKET,
timeInForce: Types.OrderTimeInForce.TIME_IN_FORCE_FOK,
side: Types.Side.SIDE_SELL,
size: openVolume,
},
],
},
});
expect(result.current.transaction.status).toEqual(VegaTxStatus.Requested);
await waitFor(() => {
expect(result.current.transaction).toEqual({
status: VegaTxStatus.Complete,
signature: txResponse.signature,
txHash: txResponse.transactionHash,
dialogOpen: true,
error: null,
});
expect(result.current.transactionResult).toEqual(txResult);
});
});
it('closes short positions', async () => {
const marketId = 'test-market';
const openVolume = '-1000';
const mockSend = jest.fn().mockResolvedValue(txResponse);
const { result } = setup({ sendTx: mockSend, pubKey });
act(() => {
result.current.submit({ marketId, openVolume });
});
expect(mockSend).toBeCalledWith(defaultWalletContext.pubKey, {
batchMarketInstructions: {
cancellations: [
{
marketId,
orderId: '',
},
],
submissions: [
{
marketId,
type: Types.OrderType.TYPE_MARKET,
timeInForce: Types.OrderTimeInForce.TIME_IN_FORCE_FOK,
side: Types.Side.SIDE_BUY,
size: openVolume.replace('-', ''),
},
],
},
});
expect(result.current.transaction.status).toEqual(VegaTxStatus.Requested);
await waitFor(() => {
expect(result.current.transaction).toEqual({
status: VegaTxStatus.Complete,
signature: txResponse.signature,
txHash: txResponse.transactionHash,
dialogOpen: true,
error: null,
});
expect(result.current.transactionResult).toEqual(txResult);
});
});
});
@@ -0,0 +1,105 @@
import { useCallback, useState } from 'react';
import type { TransactionResult } from '@vegaprotocol/wallet';
import { determineId } from '@vegaprotocol/wallet';
import { useVegaWallet, useTransactionResult } from '@vegaprotocol/wallet';
import { useVegaTransaction } from '@vegaprotocol/wallet';
import * as Sentry from '@sentry/react';
import * as Schema from '@vegaprotocol/types';
import { useOrderUpdate } from '@vegaprotocol/orders';
import type { OrderSubFieldsFragment } from '@vegaprotocol/orders';
export interface ClosingOrder {
marketId: string;
type: Schema.OrderType.TYPE_MARKET;
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK;
side: Schema.Side;
size: string;
}
export const useClosePosition = () => {
const { pubKey } = useVegaWallet();
const { send, transaction, setComplete, Dialog } = useVegaTransaction();
const [closingOrder, setClosingOrder] = useState<ClosingOrder>();
const [closingOrderResult, setClosingOrderResult] =
useState<OrderSubFieldsFragment>();
const [transactionResult, setTransactionResult] =
useState<TransactionResult>();
const waitForTransactionResult = useTransactionResult();
const waitForOrder = useOrderUpdate(transaction);
const submit = useCallback(
async ({
marketId,
openVolume,
}: {
marketId: string;
openVolume: string;
}) => {
if (!pubKey || openVolume === '0') {
return;
}
setTransactionResult(undefined);
setClosingOrder(undefined);
try {
// figure out if position is long or short and make side the opposite
const side = openVolume.startsWith('-')
? Schema.Side.SIDE_BUY
: Schema.Side.SIDE_SELL;
// volume could be prefixed with '-' if position is short, remove it
const size = openVolume.replace('-', '');
const closingOrder = {
marketId: marketId,
type: Schema.OrderType.TYPE_MARKET as const,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK as const,
side,
size,
};
setClosingOrder(closingOrder);
const command = {
batchMarketInstructions: {
cancellations: [
{
marketId,
orderId: '', // omit order id to cancel all active orders
},
],
submissions: [closingOrder],
},
};
const res = await send(pubKey, command);
if (res) {
const orderId = determineId(res.signature);
const [txResult, orderResult] = await Promise.all([
waitForTransactionResult(res.transactionHash, pubKey),
waitForOrder(orderId, pubKey),
]);
setTransactionResult(txResult);
setClosingOrderResult(orderResult);
setComplete();
}
return res;
} catch (e) {
Sentry.captureException(e);
return;
}
},
[pubKey, send, setComplete, waitForTransactionResult, waitForOrder]
);
return {
transaction,
transactionResult,
submit,
closingOrder,
closingOrderResult,
Dialog,
};
};
@@ -0,0 +1,66 @@
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
import { isOrderActive, ordersWithMarketProvider } from '@vegaprotocol/orders';
import type { OrdersQueryVariables } from '@vegaprotocol/orders';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { useMemo } from 'react';
export const useRequestClosePositionData = (
marketId?: string,
partyId?: string
) => {
const marketVariables = useMemo(
() => ({ marketId: marketId || '' }),
[marketId]
);
const orderVariables = useMemo<OrdersQueryVariables>(
() => ({ partyId: partyId || '' }),
[partyId]
);
const { data: market, loading: marketLoading } = useDataProvider({
dataProvider: marketProvider,
variables: marketVariables,
skip: !marketId,
});
const { data: marketData, loading: marketDataLoading } = useDataProvider({
dataProvider: marketDataProvider,
variables: marketVariables,
});
const { data: orderData, loading: orderDataLoading } = useDataProvider({
dataProvider: ordersWithMarketProvider,
variables: orderVariables,
skip: !partyId,
});
const orders = useMemo(() => {
if (!orderData || !market) return [];
return (
orderData
.filter((o) => {
// Filter out orders not on market for position
if (
!o ||
!o.node ||
!o.node.market ||
o.node.market.id !== market.id
) {
return false;
}
if (!isOrderActive(o.node.status)) {
return false;
}
return true;
})
// @ts-ignore o is never null as its been filtered out above
.map((o) => o.node)
);
}, [orderData, market]);
return {
market,
marketData,
orders,
loading: marketLoading || marketDataLoading || orderDataLoading,
};
};
+15 -16
View File
@@ -1,7 +1,6 @@
import { ethers } from 'ethers';
import { hexlify } from 'ethers/lib/utils';
import abi from '../abis/claim_abi.json';
import { calcGasBuffer } from '../utils';
export const UNSPENT_CODE = '0x0000000000000000000000000000000000000000';
export const SPENT_CODE = '0x0000000000000000000000000000000000000001';
@@ -43,7 +42,7 @@ export class Claim {
* was performed and mined beforehand
* @return {Promise<boolean>}
*/
public async claim({
public claim({
amount,
tranche,
expiry,
@@ -62,20 +61,20 @@ export class Claim {
r: string;
s: string;
}): Promise<ethers.ContractTransaction> {
const method = target != null ? 'claim_targeted' : 'claim_untargeted';
const args = [
{ r, s, v },
{
amount,
tranche,
expiry,
},
hexlify(country),
target,
].filter(Boolean);
const res = await this.contract.estimateGas[method](...args);
const gasLimit = calcGasBuffer(res);
return this.contract[method](...args, { gasLimit });
return this.contract[
target != null ? 'claim_targeted' : 'claim_untargeted'
](
...[
{ r, s, v },
{
amount,
tranche,
expiry,
},
hexlify(country),
target,
].filter(Boolean)
);
}
/**
@@ -1,7 +1,6 @@
import type { BigNumber } from 'ethers';
import { ethers } from 'ethers';
import abi from '../abis/erc20_bridge_abi.json';
import { calcGasBuffer } from '../utils';
export class CollateralBridge {
public contract: ethers.Contract;
@@ -14,20 +13,8 @@ export class CollateralBridge {
this.contract = new ethers.Contract(address, abi, signerOrProvider);
}
async deposit_asset(
assetSource: string,
amount: string,
vegaPublicKey: string
) {
const res = await this.contract.estimateGas.deposit_asset(
assetSource,
amount,
vegaPublicKey
);
const gasLimit = calcGasBuffer(res);
return this.contract.deposit_asset(assetSource, amount, vegaPublicKey, {
gasLimit,
});
deposit_asset(assetSource: string, amount: string, vegaPublicKey: string) {
return this.contract.deposit_asset(assetSource, amount, vegaPublicKey);
}
get_asset_source(vegaAssetId: string) {
return this.contract.get_asset_source(vegaAssetId);
@@ -50,7 +37,7 @@ export class CollateralBridge {
default_withdraw_delay() {
return this.contract.default_withdraw_delay();
}
async list_asset(
list_asset(
address: string,
vegaAssetId: string,
lifetimeLimit: string,
@@ -58,7 +45,7 @@ export class CollateralBridge {
nonce: string,
signatures: string
) {
const res = await this.contract.estimateGas.list_asset(
return this.contract.list_asset(
address,
vegaAssetId,
lifetimeLimit,
@@ -66,20 +53,8 @@ export class CollateralBridge {
nonce,
signatures
);
const gasLimit = calcGasBuffer(res);
return this.contract.list_asset(
address,
vegaAssetId,
lifetimeLimit,
withdraw_threshold,
nonce,
signatures,
{
gasLimit,
}
);
}
async withdraw_asset(
withdraw_asset(
assetSource: string,
amount: string,
target: string,
@@ -87,25 +62,13 @@ export class CollateralBridge {
nonce: string,
signatures: string
) {
const res = await this.contract.estimateGas.withdraw_asset(
assetSource,
amount,
target,
creation,
nonce,
signatures
);
const gasLimit = calcGasBuffer(res);
return this.contract.withdraw_asset(
assetSource,
amount,
target,
creation,
nonce,
signatures,
{
gasLimit,
}
signatures
);
}
@@ -1,6 +1,5 @@
import { ethers } from 'ethers';
import abi from '../abis/multisig_abi.json';
import { calcGasBuffer } from '../utils';
export class MultisigControl {
public contract: ethers.Contract;
@@ -14,20 +13,12 @@ export class MultisigControl {
this.address = address;
}
async add_signer(newSigner: string, nonce: string, signatures: string) {
const res = await this.contract.estimateGas.add_signer(
newSigner,
nonce,
signatures
);
const gasLimit = calcGasBuffer(res);
return this.contract.add_signer(newSigner, nonce, signatures, { gasLimit });
add_signer(newSigner: string, nonce: string, signatures: string) {
return this.contract.add_signer(newSigner, nonce, signatures);
}
async burn_nonce(nonce: string, signatures: string) {
const res = await this.contract.estimateGas.burn_nonce(nonce, signatures);
const gasLimit = calcGasBuffer(res);
return this.contract.burn_nonce(nonce, signatures, { gasLimit });
burn_nonce(nonce: string, signatures: string) {
return this.contract.burn_nonce(nonce, signatures);
}
get_current_threshold() {
@@ -46,43 +37,19 @@ export class MultisigControl {
return this.contract.is_valid_signer(signerAddress);
}
async remove_signer(oldSigner: string, nonce: string, signatures: string) {
const res = await this.contract.estimateGas.remove_signer(
oldSigner,
nonce,
signatures
);
const gasLimit = calcGasBuffer(res);
return this.contract.remove_signer(oldSigner, nonce, signatures, {
gasLimit,
});
remove_signer(oldSigner: string, nonce: string, signatures: string) {
return this.contract.remove_signer(oldSigner, nonce, signatures);
}
async set_threshold(newThreshold: string, nonce: string, signatures: string) {
const res = await this.contract.estimateGas.set_threshold(
newThreshold,
nonce,
signatures
);
const gasLimit = calcGasBuffer(res);
return this.contract.set_threshold(newThreshold, nonce, signatures, {
gasLimit,
});
set_threshold(newThreshold: string, nonce: string, signatures: string) {
return this.contract.set_threshold(newThreshold, nonce, signatures);
}
signers(address: string) {
return this.contract.signers(address);
}
async verify_signatures(nonce: string, message: string, signatures: string) {
const res = await this.contract.estimateGas.verify_signatures(
nonce,
message,
signatures
);
const gasLimit = calcGasBuffer(res);
return this.contract.verify_signatures(nonce, message, signatures, {
gasLimit,
});
verify_signatures(nonce: string, message: string, signatures: string) {
return this.contract.verify_signatures(nonce, message, signatures);
}
}
@@ -1,6 +1,6 @@
import { ethers } from 'ethers';
import abi from '../abis/staking_abi.json';
import { calcGasBuffer, prepend0x } from '../utils';
import { prepend0x } from '../utils';
export class StakingBridge {
public contract: ethers.Contract;
@@ -13,41 +13,20 @@ export class StakingBridge {
this.contract = new ethers.Contract(address, abi, signerOrProvider);
this.address = address;
}
async stake(amount: string, vegaPublicKey: string) {
const key = prepend0x(vegaPublicKey);
const res = await this.contract.estimateGas.stake(amount, key);
const gasLimit = calcGasBuffer(res);
return this.contract.stake(amount, key, {
gasLimit,
});
}
async remove_stake(amount: string, vegaPublicKey: string) {
const key = prepend0x(vegaPublicKey);
const res = await this.contract.estimateGas.remove_stake(amount, key);
const gasLimit = calcGasBuffer(res);
return this.contract.remove_stake(amount, key, {
gasLimit,
});
stake(amount: string, vegaPublicKey: string) {
return this.contract.stake(amount, prepend0x(vegaPublicKey));
}
async transfer_stake(
amount: string,
newAddress: string,
vegaPublicKey: string
) {
const key = prepend0x(vegaPublicKey);
const res = await this.contract.estimateGas.transfer_stake(
remove_stake(amount: string, vegaPublicKey: string) {
return this.contract.remove_stake(amount, prepend0x(vegaPublicKey));
}
transfer_stake(amount: string, newAddress: string, vegaPublicKey: string) {
return this.contract.transfer_stake(
amount,
newAddress,
key
prepend0x(vegaPublicKey)
);
const gasLimit = calcGasBuffer(res);
return this.contract.transfer_stake(amount, newAddress, key, {
gasLimit,
});
}
staking_token() {
return this.contract.staking_token();
}
@@ -1,7 +1,6 @@
import type { BigNumber } from 'ethers';
import { ethers } from 'ethers';
import erc20AbiFaucetable from '../abis/erc20_abi_faucet.json';
import { calcGasBuffer } from '../utils';
export class TokenFaucetable {
public contract: ethers.Contract;
@@ -28,17 +27,13 @@ export class TokenFaucetable {
allowance(owner: string, spender: string): Promise<BigNumber> {
return this.contract.allowance(owner, spender);
}
async approve(spender: string, amount: string) {
const res = await this.contract.estimateGas.approve(spender, amount);
const gasLimit = calcGasBuffer(res);
return this.contract.approve(spender, amount, { gasLimit });
approve(spender: string, amount: string) {
return this.contract.approve(spender, amount);
}
decimals(): Promise<number> {
return this.contract.decimals();
}
async faucet() {
const res = await this.contract.estimateGas.faucet();
const gasLimit = calcGasBuffer(res);
return this.contract.faucet({ gasLimit });
faucet() {
return this.contract.faucet();
}
}
@@ -1,6 +1,6 @@
import { ethers } from 'ethers';
import abi from '../abis/vesting_abi.json';
import { calcGasBuffer, prepend0x } from '../utils';
import { prepend0x } from '../utils';
export class TokenVesting {
public contract: ethers.Contract;
@@ -13,21 +13,12 @@ export class TokenVesting {
this.contract = new ethers.Contract(address, abi, signerOrProvider);
this.address = address;
}
async stake_tokens(amount: string, vegaPublicKey: string) {
const key = prepend0x(vegaPublicKey);
const res = await this.contract.estimateGas.stake_tokens(amount, key);
const gasLimit = calcGasBuffer(res);
return this.contract.stake_tokens(amount, key, {
gasLimit,
});
stake_tokens(amount: string, vegaPublicKey: string) {
return this.contract.stake_tokens(amount, prepend0x(vegaPublicKey));
}
async remove_stake(amount: string, vegaPublicKey: string) {
const key = prepend0x(vegaPublicKey);
const res = await this.contract.estimateGas.remove_stake(amount, key);
const gasLimit = calcGasBuffer(res);
return this.contract.remove_stake(amount, key, {
gasLimit,
});
remove_stake(amount: string, vegaPublicKey: string) {
return this.contract.remove_stake(amount, prepend0x(vegaPublicKey));
}
stake_balance(address: string, vegaPublicKey: string) {
return this.contract.stake_balance(address, prepend0x(vegaPublicKey));
@@ -47,13 +38,7 @@ export class TokenVesting {
user_total_all_tranches(address: string) {
return this.contract.user_total_all_tranches(address);
}
async withdraw_from_tranche(trancheId: number) {
const res = await this.contract.estimateGas.withdraw_from_tranche(
trancheId
);
const gasLimit = calcGasBuffer(res);
return this.contract.withdraw_from_tranche(trancheId, {
gasLimit,
});
withdraw_from_tranche(trancheId: number) {
return this.contract.withdraw_from_tranche(trancheId);
}
}
+3 -6
View File
@@ -1,7 +1,6 @@
import type { BigNumber } from 'ethers';
import { ethers } from 'ethers';
import erc20Abi from '../abis/erc20_abi.json';
import { calcGasBuffer } from '../utils';
export class Token {
public contract: ethers.Contract;
@@ -24,15 +23,13 @@ export class Token {
allowance(owner: string, spender: string): Promise<BigNumber> {
return this.contract.allowance(owner, spender);
}
async approve(spender: string, amount: string) {
const res = await this.contract.estimateGas.approve(spender, amount);
const gasLimit = calcGasBuffer(res);
return this.contract.approve(spender, amount, { gasLimit });
approve(spender: string, amount: string) {
return this.contract.approve(spender, amount);
}
decimals(): Promise<number> {
return this.contract.decimals();
}
async faucet() {
faucet() {
/* No op */
}
}
@@ -1,5 +0,0 @@
import type { BigNumber as EthersBigNumber } from 'ethers';
export function calcGasBuffer(value: EthersBigNumber): EthersBigNumber {
return value.mul(120).div(100);
}
-1
View File
@@ -1,2 +1 @@
export * from './calc-gas-buffer';
export * from './prepend-0x';
@@ -38,7 +38,6 @@ export const Checkbox = ({
checked={checked}
onCheckedChange={onCheckedChange}
disabled={disabled}
data-testid={name}
>
<CheckboxPrimitive.CheckboxIndicator className="flex justify-center items-center w-[15px] h-[15px] bg-black dark:bg-white">
{checked === 'indeterminate' ? (
+1
View File
@@ -3,6 +3,7 @@
*/
export const createDocsLinks = (docsUrl: string) => ({
NEW_TO_VEGA: `${docsUrl}/concepts/new-to-vega`,
AUCTION_TYPE_OPENING: `${docsUrl}/concepts/trading-on-vega/trading-modes#auction-type-opening`,
AUCTION_TYPE_LIQUIDITY_MONITORING: `${docsUrl}/concepts/trading-on-vega/trading-modes#auction-type-liquidity-monitoring`,
AUCTION_TYPE_PRICE_MONITORING: `${docsUrl}/concepts/trading-on-vega/trading-modes#auction-type-price-monitoring`,