Compare commits
112
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c93793a93 | ||
|
|
e265a14e69 | ||
|
|
3189fc1b37 | ||
|
|
9715b681ea | ||
|
|
3e223c24a7 | ||
|
|
51d6dd00a9 | ||
|
|
0523b56e39 | ||
|
|
1be1a78a69 | ||
|
|
1c4231f6fc | ||
|
|
22fc0e7ac1 | ||
|
|
8f0898385f | ||
|
|
db3aa7c17b | ||
|
|
416805c2a2 | ||
|
|
f28ef02c54 | ||
|
|
41f869c6c6 | ||
|
|
b75ed62072 | ||
|
|
c7c42045a5 | ||
|
|
1a1ab4db65 | ||
|
|
24a20f48e1 | ||
|
|
c1019c0ffb | ||
|
|
079a4b7fa7 | ||
|
|
fbecf0bffd | ||
|
|
f732e66546 | ||
|
|
541396eb76 | ||
|
|
3f06f56724 | ||
|
|
8a175bf2d7 | ||
|
|
eed6a83572 | ||
|
|
25c3ac8b4a | ||
|
|
9a2ac6a8ac | ||
|
|
0413ef13f3 | ||
|
|
dee486e3aa | ||
|
|
d28d238574 | ||
|
|
67315d611b | ||
|
|
8a03ca5cfe | ||
|
|
4cd980f6bf | ||
|
|
71ede25339 | ||
|
|
80f6725a9a | ||
|
|
1d726ba9e3 | ||
|
|
ba4954b52a | ||
|
|
f614ec9211 | ||
|
|
c375f74906 | ||
|
|
df8fed2af2 | ||
|
|
1c9cd3aa2a | ||
|
|
2e644de413 | ||
|
|
838c6c45c7 | ||
|
|
b733de5996 | ||
|
|
20cb4677ee | ||
|
|
4cc3bbae6f | ||
|
|
6ba8926ff7 | ||
|
|
a8565f8d2f | ||
|
|
1843b59304 | ||
|
|
937f4beeb0 | ||
|
|
460e3c03c5 | ||
|
|
3c09dce870 | ||
|
|
3347e168a4 | ||
|
|
057e0ad947 | ||
|
|
181819fb24 | ||
|
|
f46d7e4617 | ||
|
|
0a88087f47 | ||
|
|
c40d71e1ed | ||
|
|
4c7ff15f23 | ||
|
|
4c900ffb31 | ||
|
|
a2f219f2dd | ||
|
|
eaad3fa26c | ||
|
|
4ee12dfa68 | ||
|
|
f0e37e4a2f | ||
|
|
45d05b38f9 | ||
|
|
ab0b762cd2 | ||
|
|
33820440da | ||
|
|
0f0f0a35cb | ||
|
|
53c72b0eae | ||
|
|
b57b12a798 | ||
|
|
a1d3094fc8 | ||
|
|
33a044e6ad | ||
|
|
f11403b1af | ||
|
|
b9436877e5 | ||
|
|
d496758478 | ||
|
|
5f8002fb27 | ||
|
|
85d838b9a6 | ||
|
|
459defddd2 | ||
|
|
52632c19d0 | ||
|
|
48c5b5cc4c | ||
|
|
8644eac2be | ||
|
|
92febfde6e | ||
|
|
76b3cdb312 | ||
|
|
b751c5c27e | ||
|
|
b1ded718a1 | ||
|
|
7b4e618689 | ||
|
|
4269060c9c | ||
|
|
76efc3f68b | ||
|
|
32b9fae28e | ||
|
|
2ad3e68118 | ||
|
|
a505c6219a | ||
|
|
497f129097 | ||
|
|
a4d5f132a4 | ||
|
|
9e4b1c0bfc | ||
|
|
457843723b | ||
|
|
53e3326a6a | ||
|
|
4f73fdfbdf | ||
|
|
db51edca0a | ||
|
|
5000474e0a | ||
|
|
7e715d08ec | ||
|
|
a4a1c20c7c | ||
|
|
b9d57efacf | ||
|
|
e1c532cc05 | ||
|
|
e026fa6244 | ||
|
|
5f29d0ccb3 | ||
|
|
394c38c601 | ||
|
|
3c8a0b182f | ||
|
|
cc6e62cff5 | ||
|
|
855934d639 | ||
|
|
48d69ed0cc |
@@ -129,12 +129,12 @@ jobs:
|
||||
run: yarn install
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: yarn nx run ${{inputs.project}}:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
|
||||
run: yarn nx run ${{ github.event.inputs.project }}:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
|
||||
env:
|
||||
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
|
||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPESS_ETH_WALLET_MNEMONIC }}
|
||||
CYPRESS_INCLUDE_FLOWS: ${{inputs.includeFlows}}
|
||||
CYPRESS_INCLUDE_FLOWS: ${{ github.event.inputs.includeFlows }}
|
||||
|
||||
######
|
||||
## Upload logs
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
name: Capsule tests -- nightly
|
||||
name: Capsule tests -- night run
|
||||
|
||||
# This workflow runs the frontend tests against latest develop of the core to preempt breaking changes
|
||||
|
||||
@@ -106,7 +106,7 @@ jobs:
|
||||
- name: Checkout frontend mono repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
ref: master
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install root dependencies
|
||||
@@ -1,133 +0,0 @@
|
||||
name: Capsule tests -- nightly test copy
|
||||
|
||||
# This workflow runs the frontend tests against latest develop of the core to preempt breaking changes
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
nightly:
|
||||
name: Run capsule tests -- nightly
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GO111MODULE: 'on'
|
||||
steps:
|
||||
#######
|
||||
## Setup langs
|
||||
#######
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
id: go
|
||||
with:
|
||||
go-version: 1.18
|
||||
- name: Set up Node 16
|
||||
uses: actions/setup-node@v2
|
||||
id: npm
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
#######
|
||||
## Checkout capsule
|
||||
#######
|
||||
|
||||
# Checkout capsule to build local network
|
||||
- name: Checkout capsule
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: vegaprotocol/vegacapsule
|
||||
ref: v0.2.1
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
path: './capsule'
|
||||
|
||||
#######
|
||||
## Build binaries
|
||||
#######
|
||||
- name: Build capsule
|
||||
run: go install
|
||||
working-directory: capsule
|
||||
|
||||
- name: Set GOBIN
|
||||
run: echo GOBIN=$(go env GOPATH)/bin >> $GITHUB_ENV
|
||||
|
||||
- name: Install binaries
|
||||
run: vegacapsule install-bins
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
GOBIN: ${{ env.GOBIN }}
|
||||
|
||||
- name: Checkout Vega
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: vegaprotocol/vega
|
||||
ref: tm35.9
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
path: './vega'
|
||||
|
||||
- name: Install binary from Vega repo
|
||||
run: go install ./cmd/vega
|
||||
working-directory: vega
|
||||
|
||||
######
|
||||
## Start capsule
|
||||
######
|
||||
- name: Login to docker
|
||||
run: echo -n ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} | docker login https://ghcr.io -u vega-ci-bot --password-stdin
|
||||
|
||||
- name: Start nomad
|
||||
run: vegacapsule nomad &
|
||||
|
||||
- name: Bootstrap network
|
||||
run: vegacapsule network bootstrap --config-path=./net_confs/config.hcl --force
|
||||
working-directory: capsule
|
||||
|
||||
######
|
||||
## Setup a Vega wallet for our user
|
||||
######
|
||||
- name: Create passphrase
|
||||
run: echo "${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}" > ./passphrase
|
||||
- name: Create recovery
|
||||
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
|
||||
|
||||
- name: Initialize wallet
|
||||
run: vegawallet init -f --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Import wallet
|
||||
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Create public key 2
|
||||
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Start service
|
||||
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
|
||||
|
||||
######
|
||||
## Run some tests
|
||||
######
|
||||
|
||||
# Checkout front ends
|
||||
- name: Checkout frontend mono repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: yarn nx run-many --target=e2e --all --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
|
||||
env:
|
||||
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
|
||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPESS_ETH_WALLET_MNEMONIC }}
|
||||
CYPRESS_NIGHTLY_RUN: true
|
||||
CYPRESS_INCLUDE_FLOWS: 'true'
|
||||
|
||||
######
|
||||
## Upload logs
|
||||
######
|
||||
|
||||
- name: Logs
|
||||
if: ${{ always() }}
|
||||
run: vegacapsule network logs > vega-capsule-logs.txt
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: logs
|
||||
path: ./vega-capsule-logs.txt
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
@@ -12,6 +12,7 @@ NX_EXPLORER_ASSETS=1
|
||||
NX_EXPLORER_GENESIS=1
|
||||
NX_EXPLORER_GOVERNANCE=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=0
|
||||
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
|
||||
@@ -11,6 +11,7 @@ NX_EXPLORER_ASSETS=1
|
||||
NX_EXPLORER_GENESIS=1
|
||||
NX_EXPLORER_GOVERNANCE=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
|
||||
@@ -11,6 +11,7 @@ NX_EXPLORER_ASSETS=1
|
||||
NX_EXPLORER_GENESIS=1
|
||||
NX_EXPLORER_GOVERNANCE=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
|
||||
@@ -11,6 +11,7 @@ NX_EXPLORER_ASSETS=1
|
||||
NX_EXPLORER_GENESIS=1
|
||||
NX_EXPLORER_GOVERNANCE=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
|
||||
@@ -11,6 +11,7 @@ NX_EXPLORER_ASSETS=1
|
||||
NX_EXPLORER_GENESIS=1
|
||||
NX_EXPLORER_GOVERNANCE=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
|
||||
@@ -64,20 +64,21 @@ context('Node switcher', function () {
|
||||
cy.getByTestId('node-url-custom').click();
|
||||
|
||||
cy.getByTestId(customNodeBtn).within(() => {
|
||||
cy.get('input').clear().type('https://n04.d.vega.xyz/query');
|
||||
cy.get('input').clear().type('https://api.token.vega.xyz/query');
|
||||
cy.getByTestId('link').click();
|
||||
});
|
||||
validateNodeError(errorTypeTxt, nodeErrorTxt);
|
||||
});
|
||||
|
||||
afterEach('Close node switcher', function () {
|
||||
cy.getByTestId(closeDialogBtn).click();
|
||||
cy.getByTestId(closeDialogBtn).should('be.enabled').click();
|
||||
});
|
||||
|
||||
function validateNodeError(errortype, errorMsg) {
|
||||
cy.getByTestId(nodeErrorType).should('have.text', errortype, {
|
||||
timeout: 1000,
|
||||
});
|
||||
cy.getByTestId(nodeErrorType, { timeout: 10000 }).should(
|
||||
'have.text',
|
||||
errortype
|
||||
);
|
||||
cy.getByTestId(nodeErrorMsg).should('have.text', errorMsg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -23,4 +23,5 @@ NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
NX_EXPLORER_VALIDATORS=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
|
||||
@@ -13,6 +13,7 @@ NX_EXPLORER_ASSETS=1
|
||||
NX_EXPLORER_GENESIS=1
|
||||
NX_EXPLORER_GOVERNANCE=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
|
||||
@@ -58,6 +58,7 @@ There are a few different configuration options offered for this app:
|
||||
| `NX_EXPLORER_GENESIS` | Enable the genesis page for the explorer |
|
||||
| `NX_EXPLORER_GOVERNANCE` | Enable the governance page for the explorer |
|
||||
| `NX_EXPLORER_MARKETS` | Enable the markets page for the explorer |
|
||||
| `NX_EXPLORER_ORACLES` | Enable the oracles page for the explorer |
|
||||
| `NX_EXPLORER_TXS_LIST` | Enable the transactions list page for the explorer |
|
||||
| `NX_EXPLORER_NETWORK_PARAMETERS` | Enable the network parameters page for the explorer |
|
||||
| `NX_EXPLORER_PARTIES` | Enable the parties page for the explorer |
|
||||
|
||||
@@ -29,6 +29,7 @@ export const JumpToBlock = () => {
|
||||
inputType="number"
|
||||
inputName="blockNumber"
|
||||
submitHandler={handleSubmit}
|
||||
inputMin={1}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,6 +9,8 @@ interface JumpToProps {
|
||||
inputType: HTMLInputTypeAttribute;
|
||||
inputName: string;
|
||||
submitHandler: (arg0: SyntheticEvent) => void;
|
||||
inputMin?: string | number;
|
||||
inputMax?: string | number;
|
||||
}
|
||||
|
||||
export const JumpTo = ({
|
||||
@@ -18,6 +20,8 @@ export const JumpTo = ({
|
||||
inputType,
|
||||
inputName,
|
||||
submitHandler,
|
||||
inputMin,
|
||||
inputMax,
|
||||
}: JumpToProps) => {
|
||||
return (
|
||||
<form onSubmit={submitHandler}>
|
||||
@@ -35,6 +39,8 @@ export const JumpTo = ({
|
||||
name={inputName}
|
||||
placeholder={placeholder}
|
||||
className="max-w-[200px]"
|
||||
min={inputMin}
|
||||
max={inputMax}
|
||||
/>
|
||||
<Button
|
||||
data-testid="go-submit"
|
||||
|
||||
@@ -24,6 +24,7 @@ export const ENV = {
|
||||
genesis: truthy.includes(windowOrDefault('NX_EXPLORER_GENESIS')),
|
||||
governance: truthy.includes(windowOrDefault('NX_EXPLORER_GOVERNANCE')),
|
||||
markets: truthy.includes(windowOrDefault('NX_EXPLORER_MARKETS')),
|
||||
oracles: truthy.includes(windowOrDefault('NX_EXPLORER_ORACLES')),
|
||||
txsList: truthy.includes(windowOrDefault('NX_EXPLORER_TXS_LIST')),
|
||||
networkParameters: truthy.includes(
|
||||
windowOrDefault('NX_EXPLORER_NETWORK_PARAMETERS')
|
||||
|
||||
@@ -24,10 +24,10 @@ describe('NetworkParametersTable', () => {
|
||||
);
|
||||
const rows = screen.getAllByTestId('key-value-table-row');
|
||||
expect(rows[0].children[0]).toHaveTextContent(
|
||||
'Market Fee Factors Infrastructure Fee'
|
||||
'market.fee.factors.infrastructureFee'
|
||||
);
|
||||
expect(rows[1].children[0]).toHaveTextContent(
|
||||
'Market Liquidity Provision Min Lp Stake Quantum Multiple'
|
||||
'market.liquidityProvision.minLpStakeQuantumMultiple'
|
||||
);
|
||||
expect(rows[0].children[1]).toHaveTextContent('0.0005');
|
||||
expect(rows[1].children[1]).toHaveTextContent('1');
|
||||
@@ -54,10 +54,10 @@ describe('NetworkParametersTable', () => {
|
||||
);
|
||||
const rows = screen.getAllByTestId('key-value-table-row');
|
||||
expect(rows[0].children[0]).toHaveTextContent(
|
||||
'Market Fee Factors Infrastructure Fee'
|
||||
'market.fee.factors.infrastructureFee'
|
||||
);
|
||||
expect(rows[1].children[0]).toHaveTextContent(
|
||||
'Market Liquidity Provision Min Lp Stake Quantum Multiple'
|
||||
'market.liquidityProvision.minLpStakeQuantumMultiple'
|
||||
);
|
||||
expect(rows[0].children[1]).toHaveTextContent('0.0005');
|
||||
expect(rows[1].children[1]).toHaveTextContent('1');
|
||||
|
||||
@@ -16,7 +16,22 @@ import type {
|
||||
NetworkParametersQuery_networkParameters,
|
||||
} from './__generated__/NetworkParametersQuery';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import startCase from 'lodash/startCase';
|
||||
|
||||
const PERCENTAGE_PARAMS = [
|
||||
'governance.proposal.asset.requiredMajority',
|
||||
'governance.proposal.asset.requiredParticipation',
|
||||
'governance.proposal.freeform.requiredMajority',
|
||||
'governance.proposal.freeform.requiredParticipation',
|
||||
'governance.proposal.market.requiredMajority',
|
||||
'governance.proposal.market.requiredParticipation',
|
||||
'governance.proposal.updateMarket.requiredMajority',
|
||||
'governance.proposal.updateMarket.requiredMajorityLP',
|
||||
'governance.proposal.updateMarket.requiredParticipation',
|
||||
'governance.proposal.updateMarket.requiredParticipationLP',
|
||||
'governance.proposal.updateNetParam.requiredMajority',
|
||||
'governance.proposal.updateNetParam.requiredParticipation',
|
||||
'validators.vote.required',
|
||||
];
|
||||
|
||||
const BIG_NUMBER_PARAMS = [
|
||||
'spam.protection.delegation.min.tokens',
|
||||
@@ -34,22 +49,35 @@ const BIG_NUMBER_PARAMS = [
|
||||
'spam.protection.proposal.min.tokens',
|
||||
'governance.proposal.updateMarket.minProposerBalance',
|
||||
'governance.proposal.asset.minProposerBalance',
|
||||
'governance.proposal.market.minProposerBalance',
|
||||
'governance.proposal.market.minVoterBalance',
|
||||
];
|
||||
|
||||
export const renderRow = ({
|
||||
key,
|
||||
value,
|
||||
}: NetworkParametersQuery_networkParameters) => {
|
||||
export const NetworkParameterRow = ({
|
||||
row: { key, value },
|
||||
}: {
|
||||
row: NetworkParametersQuery_networkParameters;
|
||||
}) => {
|
||||
const isSyntaxRow = isJsonObject(value);
|
||||
|
||||
return (
|
||||
<KeyValueTableRow key={key} inline={!isSyntaxRow}>
|
||||
{startCase(key)}
|
||||
<KeyValueTableRow
|
||||
key={key}
|
||||
inline={!isSyntaxRow}
|
||||
id={key}
|
||||
className={
|
||||
'group target:bg-vega-pink target:text-white dark:target:bg-vega-yellow dark:target:text-black'
|
||||
}
|
||||
>
|
||||
{key}
|
||||
{isSyntaxRow ? (
|
||||
<SyntaxHighlighter data={JSON.parse(value)} />
|
||||
) : isNaN(Number(value)) ? (
|
||||
value
|
||||
) : BIG_NUMBER_PARAMS.includes(key) ? (
|
||||
addDecimalsFormatNumber(Number(value), 18)
|
||||
) : PERCENTAGE_PARAMS.includes(key) ? (
|
||||
`${formatNumber(Number(value) * 100, 0)}%`
|
||||
) : (
|
||||
formatNumber(Number(value), 4)
|
||||
)}
|
||||
@@ -103,7 +131,9 @@ export const NetworkParametersTable = ({
|
||||
);
|
||||
return (
|
||||
<KeyValueTable data-testid="parameters">
|
||||
{(ascParams || []).map((row) => renderRow(row))}
|
||||
{(ascParams || []).map((row) => (
|
||||
<NetworkParameterRow key={row.key} row={row} />
|
||||
))}
|
||||
</KeyValueTable>
|
||||
);
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { OracleSpecStatus, PropertyKeyType, ConditionOperator } from "@vegaprotocol/types";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: OracleSpecs
|
||||
// ====================================================
|
||||
|
||||
export interface OracleSpecs_oracleSpecs_filters_key {
|
||||
__typename: "PropertyKey";
|
||||
/**
|
||||
* name is the name of the property.
|
||||
*/
|
||||
name: string | null;
|
||||
/**
|
||||
* type is the type of the property.
|
||||
*/
|
||||
type: PropertyKeyType;
|
||||
}
|
||||
|
||||
export interface OracleSpecs_oracleSpecs_filters_conditions {
|
||||
__typename: "Condition";
|
||||
/**
|
||||
* value is used by the comparator.
|
||||
*/
|
||||
value: string | null;
|
||||
/**
|
||||
* comparator is the type of comparison to make on the value.
|
||||
*/
|
||||
operator: ConditionOperator;
|
||||
}
|
||||
|
||||
export interface OracleSpecs_oracleSpecs_filters {
|
||||
__typename: "Filter";
|
||||
/**
|
||||
* key is the oracle data property key targeted by the filter.
|
||||
*/
|
||||
key: OracleSpecs_oracleSpecs_filters_key;
|
||||
/**
|
||||
* conditions are the conditions that should be matched by the data to be
|
||||
* considered of interest.
|
||||
*/
|
||||
conditions: OracleSpecs_oracleSpecs_filters_conditions[] | null;
|
||||
}
|
||||
|
||||
export interface OracleSpecs_oracleSpecs_data {
|
||||
__typename: "OracleData";
|
||||
/**
|
||||
* pubKeys is the list of public keys that signed the data
|
||||
*/
|
||||
pubKeys: string[] | null;
|
||||
}
|
||||
|
||||
export interface OracleSpecs_oracleSpecs {
|
||||
__typename: "OracleSpec";
|
||||
/**
|
||||
* status describes the status of the oracle spec
|
||||
*/
|
||||
status: OracleSpecStatus;
|
||||
/**
|
||||
* id is a hash generated from the OracleSpec data.
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* RFC3339Nano creation date time
|
||||
*/
|
||||
createdAt: string;
|
||||
/**
|
||||
* RFC3339Nano last updated timestamp
|
||||
*/
|
||||
updatedAt: string | null;
|
||||
/**
|
||||
* pubKeys is the list of authorized public keys that signed the data for this
|
||||
* oracle. All the public keys in the oracle data should be contained in these
|
||||
* public keys.
|
||||
*/
|
||||
pubKeys: string[] | null;
|
||||
/**
|
||||
* filters describes which oracle data are considered of interest or not for
|
||||
* the product (or the risk model).
|
||||
*/
|
||||
filters: OracleSpecs_oracleSpecs_filters[] | null;
|
||||
/**
|
||||
* data list all the oracle data broadcast to this spec
|
||||
*/
|
||||
data: OracleSpecs_oracleSpecs_data[];
|
||||
}
|
||||
|
||||
export interface OracleSpecs {
|
||||
/**
|
||||
* All registered oracle specs
|
||||
*/
|
||||
oracleSpecs: OracleSpecs_oracleSpecs[] | null;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import type { OracleSpecs as OracleSpecsQuery } from './__generated__/OracleSpecs';
|
||||
|
||||
import React from 'react';
|
||||
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { RouteTitle } from '../../components/route-title';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { SubHeading } from '../../components/sub-heading';
|
||||
|
||||
const ORACLE_SPECS_QUERY = gql`
|
||||
query OracleSpecs {
|
||||
oracleSpecs {
|
||||
status
|
||||
id
|
||||
createdAt
|
||||
updatedAt
|
||||
pubKeys
|
||||
filters {
|
||||
key {
|
||||
name
|
||||
type
|
||||
}
|
||||
conditions {
|
||||
value
|
||||
operator
|
||||
}
|
||||
}
|
||||
data {
|
||||
pubKeys
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Oracles = () => {
|
||||
const { data } = useQuery<OracleSpecsQuery>(ORACLE_SPECS_QUERY);
|
||||
|
||||
return (
|
||||
<section>
|
||||
<RouteTitle data-testid="oracle-specs-heading">{t('Oracles')}</RouteTitle>
|
||||
{data?.oracleSpecs
|
||||
? data.oracleSpecs.map((o) => (
|
||||
<React.Fragment key={o.id}>
|
||||
<SubHeading>{o.id}</SubHeading>
|
||||
<SyntaxHighlighter data={o} />
|
||||
</React.Fragment>
|
||||
))
|
||||
: null}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Oracles;
|
||||
@@ -8,5 +8,6 @@ export const Routes = {
|
||||
GENESIS: 'genesis',
|
||||
GOVERNANCE: 'governance',
|
||||
MARKETS: 'markets',
|
||||
ORACLES: 'oracles',
|
||||
NETWORK_PARAMETERS: 'network-parameters',
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import BlockPage from './blocks';
|
||||
import Governance from './governance';
|
||||
import Home from './home';
|
||||
import Markets from './markets';
|
||||
import Oracles from './oracles';
|
||||
import Party from './parties';
|
||||
import { Parties } from './parties/home';
|
||||
import { Party as PartySingle } from './parties/id';
|
||||
@@ -84,6 +85,17 @@ const marketsRoutes = flags.markets
|
||||
]
|
||||
: [];
|
||||
|
||||
const oraclesRoutes = flags.oracles
|
||||
? [
|
||||
{
|
||||
path: Routes.ORACLES,
|
||||
name: 'Oracles',
|
||||
text: t('Oracles'),
|
||||
element: <Oracles />,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
||||
const networkParametersRoutes = flags.networkParameters
|
||||
? [
|
||||
{
|
||||
@@ -154,6 +166,7 @@ const routerConfig = [
|
||||
...genesisRoutes,
|
||||
...governanceRoutes,
|
||||
...marketsRoutes,
|
||||
...oraclesRoutes,
|
||||
...networkParametersRoutes,
|
||||
...validators,
|
||||
];
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { BrowserTracing } from '@sentry/tracing';
|
||||
import { StrictMode } from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import './styles.css';
|
||||
|
||||
import App from './app/app';
|
||||
import { ENV } from './app/config/env';
|
||||
import { StrictMode } from 'react';
|
||||
|
||||
const { dsn } = ENV;
|
||||
|
||||
@@ -19,12 +19,13 @@ if (dsn) {
|
||||
environment: ENV.envName,
|
||||
});
|
||||
}
|
||||
const rootElement = document.getElementById('root');
|
||||
const root = rootElement && createRoot(rootElement);
|
||||
|
||||
ReactDOM.render(
|
||||
root?.render(
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</StrictMode>,
|
||||
document.getElementById('root')
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
@@ -12,8 +12,9 @@ module.exports = defineConfig({
|
||||
supportFile: './src/support/index.ts',
|
||||
video: true,
|
||||
videoUploadOnPasses: false,
|
||||
videosFolder: '../../dist/cypress/apps/explorer-e2e/videos',
|
||||
screenshotsFolder: '../../dist/cypress/apps/explorer-e2e/screenshots',
|
||||
videosFolder: '../../dist/cypress/apps/simple-trading-app-e2e/videos',
|
||||
screenshotsFolder:
|
||||
'../../dist/cypress/apps/simple-trading-app-e2e/screenshots',
|
||||
chromeWebSecurity: false,
|
||||
viewportWidth: 1440,
|
||||
viewportHeight: 900,
|
||||
|
||||
@@ -5,18 +5,9 @@ import { generateMarketTags } from '../support/mocks/generate-market-tags';
|
||||
import { generateMarketPositions } from '../support/mocks/generate-market-positions';
|
||||
import { generateEstimateOrder } from '../support/mocks/generate-estimate-order';
|
||||
import { generatePartyBalance } from '../support/mocks/generate-party-balance';
|
||||
|
||||
const connectVegaWallet = () => {
|
||||
const form = 'rest-connector-form';
|
||||
const walletName = Cypress.env('TRADING_TEST_VEGA_WALLET_NAME');
|
||||
const walletPassphrase = Cypress.env('TRADING_TEST_VEGA_WALLET_PASSPHRASE');
|
||||
|
||||
cy.getByTestId('connect-vega-wallet').click();
|
||||
cy.getByTestId('connectors-list').find('button').click();
|
||||
cy.getByTestId(form).find('#wallet').click().type(walletName);
|
||||
cy.getByTestId(form).find('#passphrase').click().type(walletPassphrase);
|
||||
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
|
||||
};
|
||||
import { generatePartyMarketData } from '../support/mocks/generate-party-market-data';
|
||||
import { generateMarketMarkPrice } from '../support/mocks/generate-market-mark-price';
|
||||
import { connectVegaWallet } from '../support/connect-wallet';
|
||||
|
||||
describe('Market trade', () => {
|
||||
let markets;
|
||||
@@ -28,6 +19,8 @@ describe('Market trade', () => {
|
||||
aliasQuery(req, 'MarketPositions', generateMarketPositions());
|
||||
aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
|
||||
aliasQuery(req, 'PartyBalanceQuery', generatePartyBalance());
|
||||
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
|
||||
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
|
||||
});
|
||||
cy.visit('/markets');
|
||||
cy.wait('@SimpleMarkets').then((response) => {
|
||||
@@ -36,6 +29,7 @@ describe('Market trade', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('side selector should work well', () => {
|
||||
if (markets?.length) {
|
||||
cy.visit(`/trading/${markets[0].id}`);
|
||||
@@ -53,7 +47,7 @@ describe('Market trade', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('mobile view should work well', () => {
|
||||
it('side selector mobile view should work well', () => {
|
||||
if (markets?.length) {
|
||||
cy.viewport('iphone-xr');
|
||||
cy.visit(`/trading/${markets[0].id}`);
|
||||
@@ -85,6 +79,79 @@ describe('Market trade', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('size slider should work well', () => {
|
||||
if (markets?.length) {
|
||||
cy.visit(`/trading/${markets[1].id}`);
|
||||
connectVegaWallet();
|
||||
cy.get('#step-1-control [aria-label^="Selected value"]').click();
|
||||
cy.get('button[aria-label="Open short position"]').click();
|
||||
cy.get('#step-2-control').click();
|
||||
cy.get('#step-2-panel')
|
||||
.find('dd')
|
||||
.eq(0)
|
||||
.find('button')
|
||||
.should('have.text', '1');
|
||||
cy.get('#step-2-panel').find('[role="slider"]').type('{rightarrow}');
|
||||
|
||||
cy.get('#step-2-panel')
|
||||
.find('dd')
|
||||
.eq(0)
|
||||
.find('button')
|
||||
.should('have.text', '2');
|
||||
}
|
||||
});
|
||||
|
||||
it('percentage selection should work well', () => {
|
||||
if (markets?.length) {
|
||||
cy.visit(`/trading/${markets[1].id}`);
|
||||
connectVegaWallet();
|
||||
cy.get('#step-1-control [aria-label^="Selected value"]').click();
|
||||
cy.get('button[aria-label="Open short position"]').click();
|
||||
cy.get('#step-2-control').click();
|
||||
cy.get('#step-2-panel')
|
||||
.find('dd')
|
||||
.eq(0)
|
||||
.find('button')
|
||||
.should('have.text', '1');
|
||||
cy.getByTestId('percentage-selector')
|
||||
.find('button')
|
||||
.contains('Max')
|
||||
.click();
|
||||
cy.get('#step-2-panel')
|
||||
.find('dd')
|
||||
.eq(0)
|
||||
.find('button')
|
||||
.should('have.text', '21');
|
||||
}
|
||||
});
|
||||
|
||||
it('size input should work well', () => {
|
||||
if (markets?.length) {
|
||||
cy.visit(`/trading/${markets[1].id}`);
|
||||
connectVegaWallet();
|
||||
cy.get('#step-1-control [aria-label^="Selected value"]').click();
|
||||
cy.get('button[aria-label="Open short position"]').click();
|
||||
cy.get('#step-2-control').click();
|
||||
cy.get('#step-2-panel')
|
||||
.find('dd')
|
||||
.eq(0)
|
||||
.find('button')
|
||||
.should('have.text', '1');
|
||||
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
|
||||
cy.get('#step-2-panel')
|
||||
.find('dd')
|
||||
.eq(0)
|
||||
.find('input')
|
||||
.type('{backspace}2');
|
||||
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
|
||||
cy.get('#step-2-panel')
|
||||
.find('dd')
|
||||
.eq(0)
|
||||
.find('button')
|
||||
.should('have.text', '2');
|
||||
}
|
||||
});
|
||||
|
||||
it('order review should display proper calculations', () => {
|
||||
if (markets?.length) {
|
||||
cy.visit(`/trading/${markets[0].id}`);
|
||||
@@ -94,7 +161,7 @@ describe('Market trade', () => {
|
||||
.find('dl')
|
||||
.eq(1)
|
||||
.find('dd div')
|
||||
.should('have.text', '3.44055');
|
||||
.should('have.text', '25.78726');
|
||||
cy.getByTestId('key-value-table')
|
||||
.find('dl')
|
||||
.eq(2)
|
||||
@@ -104,7 +171,7 @@ describe('Market trade', () => {
|
||||
.find('dl')
|
||||
.eq(3)
|
||||
.find('dd div')
|
||||
.should('have.text', '-785.81045');
|
||||
.should('have.text', ' - ');
|
||||
cy.getByTestId('place-order').click();
|
||||
cy.getByTestId('dialog-title').should(
|
||||
'have.text',
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import {
|
||||
connectVegaWallet,
|
||||
disconnectVegaWallet,
|
||||
} from '../support/connect-wallet';
|
||||
|
||||
describe('Portfolio page', () => {
|
||||
afterEach(() => {
|
||||
disconnectVegaWallet();
|
||||
});
|
||||
|
||||
it('button for wallet connect should work', () => {
|
||||
cy.visit('/');
|
||||
cy.get('[href="/portfolio"]').eq(0).click();
|
||||
cy.getByTestId('connect-vega-wallet-text').should('be.visible');
|
||||
connectVegaWallet();
|
||||
cy.getByTestId('connect-vega-wallet-text').should('not.exist');
|
||||
});
|
||||
|
||||
it('certain tabs should exist', () => {
|
||||
cy.visit('/portfolio');
|
||||
connectVegaWallet();
|
||||
cy.getByTestId('Assets').should('exist');
|
||||
cy.getByTestId('tab-assets').should('exist');
|
||||
|
||||
cy.getByTestId('Positions').click();
|
||||
cy.getByTestId('tab-positions').should('exist');
|
||||
|
||||
cy.getByTestId('Orders').click();
|
||||
cy.getByTestId('tab-orders').should('exist');
|
||||
|
||||
cy.getByTestId('Fills').click();
|
||||
cy.getByTestId('tab-fills').should('exist');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
export const connectVegaWallet = () => {
|
||||
const form = 'rest-connector-form';
|
||||
const walletName = Cypress.env('TRADING_TEST_VEGA_WALLET_NAME');
|
||||
const walletPassphrase = Cypress.env('TRADING_TEST_VEGA_WALLET_PASSPHRASE');
|
||||
|
||||
cy.getByTestId('connect-vega-wallet').click();
|
||||
cy.getByTestId('connectors-list').find('button').click();
|
||||
cy.getByTestId(form).find('#wallet').click().type(walletName);
|
||||
cy.getByTestId(form).find('#passphrase').click().type(walletPassphrase);
|
||||
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
|
||||
};
|
||||
|
||||
export const disconnectVegaWallet = () => {
|
||||
cy.getByTestId('connect-vega-wallet').click();
|
||||
cy.getByTestId('disconnect').click();
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
export const generateMarketMarkPrice = () => {
|
||||
return {
|
||||
market: {
|
||||
decimalPlaces: 5,
|
||||
data: { markPrice: '692748', __typename: 'MarketData' },
|
||||
__typename: 'Market',
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -2,6 +2,30 @@ export const generateMarketPositions = () => {
|
||||
return {
|
||||
party: {
|
||||
id: '2e1ef32e5804e14232406aebaad719087d326afa5c648b7824d0823d8a46c8d1',
|
||||
accounts: [
|
||||
{
|
||||
type: 'General',
|
||||
asset: {
|
||||
decimals: 5,
|
||||
},
|
||||
balance: '400000000000000000000',
|
||||
market: {
|
||||
id: '2751c508f9759761f912890f37fb3f97a00300bf7685c02a56a86e05facfe221',
|
||||
__typename: 'Market',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'Margin',
|
||||
asset: {
|
||||
decimals: 5,
|
||||
},
|
||||
balance: '265329',
|
||||
market: {
|
||||
id: 'first-btcusd-id',
|
||||
__typename: 'Market',
|
||||
},
|
||||
},
|
||||
],
|
||||
positionsConnection: {
|
||||
edges: [
|
||||
{
|
||||
@@ -9,10 +33,6 @@ export const generateMarketPositions = () => {
|
||||
openVolume: '3',
|
||||
market: {
|
||||
id: '2751c508f9759761f912890f37fb3f97a00300bf7685c02a56a86e05facfe221',
|
||||
accounts: [
|
||||
{ balance: '0', __typename: 'Account' },
|
||||
{ balance: '0', __typename: 'Account' },
|
||||
],
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'Position',
|
||||
@@ -24,10 +44,6 @@ export const generateMarketPositions = () => {
|
||||
openVolume: '12',
|
||||
market: {
|
||||
id: 'first-btcusd-id',
|
||||
accounts: [
|
||||
{ balance: '10', __typename: 'Account' },
|
||||
{ balance: '15', __typename: 'Account' },
|
||||
],
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'Position',
|
||||
|
||||
@@ -4,6 +4,7 @@ export const generatePartyBalance = () => {
|
||||
accounts: [
|
||||
{
|
||||
balance: '88474051',
|
||||
type: 'General',
|
||||
asset: {
|
||||
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
symbol: 'tDAI',
|
||||
@@ -15,6 +16,7 @@ export const generatePartyBalance = () => {
|
||||
},
|
||||
{
|
||||
balance: '100000000',
|
||||
type: 'General',
|
||||
asset: {
|
||||
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
|
||||
symbol: 'tEURO',
|
||||
@@ -26,6 +28,7 @@ export const generatePartyBalance = () => {
|
||||
},
|
||||
{
|
||||
balance: '3412867',
|
||||
type: 'General',
|
||||
asset: {
|
||||
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
symbol: 'tDAI',
|
||||
@@ -37,6 +40,7 @@ export const generatePartyBalance = () => {
|
||||
},
|
||||
{
|
||||
balance: '70007',
|
||||
type: 'General',
|
||||
asset: {
|
||||
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
symbol: 'tDAI',
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
export const generatePartyMarketData = () => {
|
||||
return {
|
||||
party: {
|
||||
id: '2e1ef32e5804e14232406aebaad719087d326afa5c648b7824d0823d8a46c8d1',
|
||||
accounts: [
|
||||
{
|
||||
type: 'General',
|
||||
balance: '1200000',
|
||||
asset: { id: 'fBTC', decimals: 5, __typename: 'Asset' },
|
||||
market: null,
|
||||
__typename: 'Account',
|
||||
},
|
||||
],
|
||||
marginsConnection: { edges: null, __typename: 'MarginConnection' },
|
||||
positionsConnection: { edges: null, __typename: 'PositionConnection' },
|
||||
__typename: 'Party',
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -17,8 +17,11 @@ NX_INCOMING_HOOK_BODY=$INCOMING_HOOK_BODY
|
||||
NX_URL=$URL
|
||||
NX_DEPLOY_URL=$DEPLOY_URL
|
||||
NX_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
|
||||
|
||||
NX_VEGA_CONFIG_URL="https://static.vega.xyz/assets/testnet-network.json"
|
||||
NX_VEGA_ENV = 'TESTNET'
|
||||
NX_VEGA_URL="https://lb.testnet.vega.xyz/query"
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789/api/v1
|
||||
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\"}
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||
|
||||
@@ -3,3 +3,7 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/devnet-network.json
|
||||
NX_VEGA_URL=https://n04.d.vega.xyz/query
|
||||
NX_VEGA_ENV=DEVNET
|
||||
NX_VEGA_REST=https://n04.d.vega.xyz/datanode/rest
|
||||
NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\"}
|
||||
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
|
||||
|
||||
@@ -3,3 +3,7 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/mainnet-network.json
|
||||
NX_VEGA_URL=https://api.token.vega.xyz/query
|
||||
NX_VEGA_ENV=MAINNET
|
||||
NX_VEGA_REST=https://api.token.vega.xyz/
|
||||
NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
|
||||
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://etherscan.io
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz
|
||||
|
||||
@@ -3,3 +3,7 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet1-network.json
|
||||
NX_VEGA_URL=https://n03.s.vega.xyz/query
|
||||
NX_VEGA_ENV=STAGNET
|
||||
NX_VEGA_REST=https://n03.s.vega.xyz/datanode/rest
|
||||
NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
|
||||
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
NX_VEGA_EXPLORER_URL=https://staging.explorer.vega.xyz
|
||||
|
||||
@@ -3,3 +3,7 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet2-network.json
|
||||
NX_VEGA_URL=https://n03.stagnet2.vega.xyz/query
|
||||
NX_VEGA_ENV=STAGNET2
|
||||
NX_VEGA_REST=https://n01.stagnet2.vega.xyz/datanode/rest
|
||||
NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
|
||||
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
NX_VEGA_EXPLORER_URL=https://staging2.explorer.vega.xyz
|
||||
|
||||
@@ -3,3 +3,7 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json
|
||||
NX_VEGA_URL=https://lb.testnet.vega.xyz/query
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_VEGA_REST=https://lb.testnet.vega.xyz/datanode/rest
|
||||
NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
|
||||
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { createClient } from './lib/apollo-client';
|
||||
import { ThemeContext } from '@vegaprotocol/react-helpers';
|
||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
import { EnvironmentProvider, NetworkLoader } from '@vegaprotocol/environment';
|
||||
import { createClient } from './lib/apollo-client';
|
||||
import {
|
||||
VegaConnectDialog,
|
||||
VegaManageDialog,
|
||||
@@ -13,14 +14,12 @@ import '../styles.scss';
|
||||
import { AppLoader } from './components/app-loader';
|
||||
import Header from './components/header';
|
||||
import { Main } from './components/main';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import LocalContext from './context/local-context';
|
||||
import useLocalValues from './hooks/use-local-values';
|
||||
|
||||
function App() {
|
||||
const localValues = useLocalValues();
|
||||
const [theme, toggleTheme] = useThemeSwitcher();
|
||||
const [vegaWallet, setVegaWallet] = useState({
|
||||
connect: false,
|
||||
manage: false,
|
||||
});
|
||||
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const onToggle = () => setMenuOpen(!menuOpen);
|
||||
@@ -36,28 +35,23 @@ function App() {
|
||||
<ThemeContext.Provider value={theme}>
|
||||
<NetworkLoader createClient={createClient}>
|
||||
<VegaWalletProvider>
|
||||
<AppLoader>
|
||||
<div className="max-h-full min-h-full dark:bg-lite-black dark:text-white-60 bg-white text-black-60 grid grid-rows-[min-content,1fr]">
|
||||
<Header
|
||||
setVegaWallet={setVegaWallet}
|
||||
toggleTheme={toggleTheme}
|
||||
/>
|
||||
<Main isMenuOpen={menuOpen} onToggle={onToggle} />
|
||||
<VegaConnectDialog
|
||||
connectors={Connectors}
|
||||
dialogOpen={vegaWallet.connect}
|
||||
setDialogOpen={(open) =>
|
||||
setVegaWallet((x) => ({ ...x, connect: open }))
|
||||
}
|
||||
/>
|
||||
<VegaManageDialog
|
||||
dialogOpen={vegaWallet.manage}
|
||||
setDialogOpen={(open) =>
|
||||
setVegaWallet((x) => ({ ...x, manage: open }))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</AppLoader>
|
||||
<LocalContext.Provider value={localValues}>
|
||||
<AppLoader>
|
||||
<div className="max-h-full min-h-full dark:bg-lite-black dark:text-white-60 bg-white text-black-60 grid grid-rows-[min-content,1fr]">
|
||||
<Header toggleTheme={toggleTheme} />
|
||||
<Main isMenuOpen={menuOpen} onToggle={onToggle} />
|
||||
<VegaConnectDialog
|
||||
connectors={Connectors}
|
||||
dialogOpen={localValues.vegaWalletDialog.connect}
|
||||
setDialogOpen={localValues.vegaWalletDialog.setConnect}
|
||||
/>
|
||||
<VegaManageDialog
|
||||
dialogOpen={localValues.vegaWalletDialog.manage}
|
||||
setDialogOpen={localValues.vegaWalletDialog.setManage}
|
||||
/>
|
||||
</div>
|
||||
</AppLoader>
|
||||
</LocalContext.Provider>
|
||||
</VegaWalletProvider>
|
||||
</NetworkLoader>
|
||||
</ThemeContext.Provider>
|
||||
|
||||
+6
@@ -3,6 +3,8 @@
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AccountType } from "@vegaprotocol/types";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: PartyBalanceQuery
|
||||
// ====================================================
|
||||
@@ -29,6 +31,10 @@ export interface PartyBalanceQuery_party_accounts_asset {
|
||||
|
||||
export interface PartyBalanceQuery_party_accounts {
|
||||
__typename: "Account";
|
||||
/**
|
||||
* Account type (General, Margin, etc)
|
||||
*/
|
||||
type: AccountType;
|
||||
/**
|
||||
* Balance as string - current account balance (approx. as balances can be updated several times per second)
|
||||
*/
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
PartyBalanceQuery_party_accounts_asset,
|
||||
} from './__generated__/PartyBalanceQuery';
|
||||
import { DealTicketBalance } from './deal-ticket-balance';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
|
||||
const tDAI: PartyBalanceQuery_party_accounts_asset = {
|
||||
__typename: 'Asset',
|
||||
@@ -17,6 +18,7 @@ const tDAI: PartyBalanceQuery_party_accounts_asset = {
|
||||
const accounts: PartyBalanceQuery_party_accounts[] = [
|
||||
{
|
||||
__typename: 'Account',
|
||||
type: AccountType.General,
|
||||
balance: '1000000',
|
||||
asset: tDAI,
|
||||
},
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { DealTicketQuery_market_tradableInstrument_instrument_product_settl
|
||||
import type { PartyBalanceQuery_party_accounts } from './__generated__/PartyBalanceQuery';
|
||||
import { useSettlementAccount } from '../../hooks/use-settlement-account';
|
||||
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
|
||||
interface DealTicketBalanceProps {
|
||||
settlementAsset: DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset;
|
||||
@@ -20,7 +21,11 @@ export const DealTicketBalance = ({
|
||||
}: DealTicketBalanceProps) => {
|
||||
const settlementAssetId = settlementAsset?.id;
|
||||
const settlementAssetSymbol = settlementAsset?.symbol;
|
||||
const settlementAccount = useSettlementAccount(settlementAssetId, accounts);
|
||||
const settlementAccount = useSettlementAccount(
|
||||
settlementAssetId,
|
||||
accounts,
|
||||
AccountType.General
|
||||
);
|
||||
const formatedNumber =
|
||||
settlementAccount?.balance &&
|
||||
settlementAccount.asset.decimals &&
|
||||
|
||||
@@ -17,6 +17,7 @@ const PARTY_BALANCE_QUERY = gql`
|
||||
query PartyBalanceQuery($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
accounts {
|
||||
type
|
||||
balance
|
||||
asset {
|
||||
id
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
SliderRoot,
|
||||
SliderThumb,
|
||||
SliderTrack,
|
||||
SliderRange,
|
||||
Button,
|
||||
Input,
|
||||
FormGroup,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
|
||||
interface DealTicketSizeProps {
|
||||
step: number;
|
||||
min: number;
|
||||
max: number;
|
||||
value: number;
|
||||
onValueChange: (value: number[]) => void;
|
||||
name: string;
|
||||
quoteName: string;
|
||||
price: string;
|
||||
estCloseOut: string;
|
||||
estMargin: string;
|
||||
positionDecimalPlaces: number;
|
||||
}
|
||||
|
||||
const getSizeLabel = (value: number): string => {
|
||||
const MIN_LABEL = 'Min';
|
||||
const MAX_LABEL = 'Max';
|
||||
if (value === 0) {
|
||||
return MIN_LABEL;
|
||||
} else if (value === 100) {
|
||||
return MAX_LABEL;
|
||||
}
|
||||
|
||||
return `${value}%`;
|
||||
};
|
||||
|
||||
export const DealTicketSize = ({
|
||||
value,
|
||||
step,
|
||||
min,
|
||||
max,
|
||||
price,
|
||||
quoteName,
|
||||
onValueChange,
|
||||
estCloseOut,
|
||||
positionDecimalPlaces,
|
||||
}: DealTicketSizeProps) => {
|
||||
const sizeRatios = [0, 25, 50, 75, 100];
|
||||
const [inputValue, setInputValue] = useState(value);
|
||||
const [isInputVisible, setIsInputVisible] = useState(false);
|
||||
|
||||
const onInputValueChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = parseFloat(event.target.value);
|
||||
const isLessThanMin = value < min;
|
||||
const isMoreThanMax = value > max;
|
||||
if (value) {
|
||||
if (isLessThanMin) {
|
||||
onValueChange([min]);
|
||||
} else if (isMoreThanMax) {
|
||||
onValueChange([max]);
|
||||
} else {
|
||||
onValueChange([value]);
|
||||
}
|
||||
}
|
||||
setInputValue(value);
|
||||
},
|
||||
[min, max, onValueChange, setInputValue]
|
||||
);
|
||||
|
||||
const onButtonValueChange = useCallback(
|
||||
(size: number) => {
|
||||
if (isInputVisible) {
|
||||
setIsInputVisible(false);
|
||||
}
|
||||
const newVal = new BigNumber(size)
|
||||
.decimalPlaces(positionDecimalPlaces)
|
||||
.toNumber();
|
||||
onValueChange([newVal]);
|
||||
setInputValue(newVal);
|
||||
},
|
||||
[isInputVisible, onValueChange, positionDecimalPlaces]
|
||||
);
|
||||
|
||||
const toggleInput = useCallback(() => {
|
||||
setIsInputVisible(!isInputVisible);
|
||||
}, [isInputVisible]);
|
||||
|
||||
const onInputEnter = useCallback(
|
||||
(event: React.KeyboardEvent) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.stopPropagation();
|
||||
toggleInput();
|
||||
}
|
||||
},
|
||||
[toggleInput]
|
||||
);
|
||||
|
||||
return max === 0 ? (
|
||||
<p>Not enough balance to trade</p>
|
||||
) : (
|
||||
<div>
|
||||
<div className="flex justify-between text-black dark:text-white mb-8">
|
||||
<span>{min}</span>
|
||||
<span>{max}</span>
|
||||
</div>
|
||||
<SliderRoot
|
||||
className="mb-8"
|
||||
value={[value]}
|
||||
onValueChange={onValueChange}
|
||||
step={step}
|
||||
min={min}
|
||||
max={max}
|
||||
>
|
||||
<SliderTrack className="bg-lightGrey dark:bg-offBlack">
|
||||
<SliderRange className="!bg-black dark:!bg-white" />
|
||||
</SliderTrack>
|
||||
<SliderThumb />
|
||||
</SliderRoot>
|
||||
|
||||
<div
|
||||
data-testid="percentage-selector"
|
||||
className="flex w-full justify-between text-black dark:text-white mb-32"
|
||||
>
|
||||
{sizeRatios.map((size, index) => {
|
||||
const proportionalSize = size ? (size / 100) * max : min;
|
||||
return (
|
||||
<Button
|
||||
variant="inline-link"
|
||||
className="no-underline !text-blue"
|
||||
onClick={() => onButtonValueChange(proportionalSize)}
|
||||
key={index}
|
||||
>
|
||||
{getSizeLabel(size)}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<dl className="text-black dark:text-white">
|
||||
<div className="flex items-center justify-between mb-8">
|
||||
<dt>
|
||||
<span>{t('Size')}</span>
|
||||
|
||||
<small>({quoteName})</small>
|
||||
</dt>
|
||||
<dd className="flex justify-end w-full">
|
||||
<FormGroup
|
||||
className="mb-0 flex items-center"
|
||||
labelClassName="mr-8 sr-only"
|
||||
label="Enter Size"
|
||||
labelFor="trade-size-input"
|
||||
>
|
||||
{isInputVisible ? (
|
||||
<>
|
||||
<Input
|
||||
id="input-order-size-market"
|
||||
type="number"
|
||||
step={step}
|
||||
min={min}
|
||||
max={max}
|
||||
className="w-full"
|
||||
value={inputValue}
|
||||
onKeyDown={onInputEnter}
|
||||
onChange={onInputValueChange}
|
||||
/>
|
||||
<Button
|
||||
variant="inline-link"
|
||||
className="no-underline !text-blue"
|
||||
onClick={toggleInput}
|
||||
>
|
||||
{t('set')}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<Button
|
||||
variant="inline-link"
|
||||
className="no-underline !text-blue"
|
||||
onClick={toggleInput}
|
||||
>
|
||||
{value}
|
||||
</Button>
|
||||
)}
|
||||
</FormGroup>
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex justify-between mb-8">
|
||||
<dt>{t('Est. price')}</dt>
|
||||
<dd>{price}</dd>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<dt>{t('Est. close out')}</dt>
|
||||
<dd>{estCloseOut}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,29 +1,34 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { Stepper } from '../stepper';
|
||||
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
||||
import { InputError } from '@vegaprotocol/ui-toolkit';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import {
|
||||
DealTicketAmount,
|
||||
getDialogTitle,
|
||||
getDialogIntent,
|
||||
getDialogIcon,
|
||||
getOrderDialogTitle,
|
||||
getOrderDialogIntent,
|
||||
getOrderDialogIcon,
|
||||
MarketSelector,
|
||||
} from '@vegaprotocol/deal-ticket';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
import { VegaTxStatus } from '@vegaprotocol/wallet';
|
||||
import { useVegaWallet, VegaTxStatus } from '@vegaprotocol/wallet';
|
||||
import { t, addDecimal, toDecimal } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
getDefaultOrder,
|
||||
useOrderValidation,
|
||||
useOrderSubmit,
|
||||
OrderFeedback,
|
||||
validateSize,
|
||||
} from '@vegaprotocol/orders';
|
||||
import { DealTicketSize } from './deal-ticket-size';
|
||||
import MarketNameRenderer from '../simple-market-list/simple-market-renderer';
|
||||
import SideSelector, { SIDE_NAMES } from './side-selector';
|
||||
import ReviewTrade from './review-trade';
|
||||
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
|
||||
import useOrderCloseOut from '../../hooks/use-order-closeout';
|
||||
import useOrderMargin from '../../hooks/use-order-margin';
|
||||
import useMaximumPositionSize from '../../hooks/use-maximum-position-size';
|
||||
|
||||
interface DealTicketMarketProps {
|
||||
market: DealTicketQuery_market;
|
||||
@@ -36,28 +41,55 @@ export const DealTicketSteps = ({
|
||||
}: DealTicketMarketProps) => {
|
||||
const navigate = useNavigate();
|
||||
const setMarket = useCallback(
|
||||
(marketId) => {
|
||||
(marketId: string) => {
|
||||
navigate(`/trading/${marketId}`);
|
||||
},
|
||||
[navigate]
|
||||
);
|
||||
|
||||
const {
|
||||
register,
|
||||
control,
|
||||
handleSubmit,
|
||||
watch,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm<Order>({
|
||||
mode: 'onChange',
|
||||
defaultValues: getDefaultOrder(market),
|
||||
});
|
||||
|
||||
const [max, setMax] = useState<number | null>(null);
|
||||
const step = toDecimal(market.positionDecimalPlaces);
|
||||
const orderType = watch('type');
|
||||
const orderTimeInForce = watch('timeInForce');
|
||||
const orderSide = watch('side');
|
||||
const orderSize = watch('size');
|
||||
const order = watch();
|
||||
const estCloseOut = useOrderCloseOut({ order, market, partyData });
|
||||
const { keypair } = useVegaWallet();
|
||||
const estMargin = useOrderMargin({
|
||||
order,
|
||||
market,
|
||||
partyId: keypair?.pub || '',
|
||||
});
|
||||
|
||||
const maxTrade = useMaximumPositionSize({
|
||||
partyId: keypair?.pub || '',
|
||||
accounts: partyData?.party?.accounts || [],
|
||||
marketId: market.id,
|
||||
settlementAssetId:
|
||||
market.tradableInstrument.instrument.product.settlementAsset.id,
|
||||
price: market?.depth?.lastTrade?.price,
|
||||
order,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setMax(
|
||||
new BigNumber(maxTrade)
|
||||
.decimalPlaces(market.positionDecimalPlaces)
|
||||
.toNumber()
|
||||
);
|
||||
}, [maxTrade, market.positionDecimalPlaces]);
|
||||
|
||||
const { message: invalidText, isDisabled } = useOrderValidation({
|
||||
step,
|
||||
@@ -70,6 +102,16 @@ export const DealTicketSteps = ({
|
||||
const { submit, transaction, finalizedOrder, TransactionDialog } =
|
||||
useOrderSubmit(market);
|
||||
|
||||
const onSizeChange = (value: number[]) => {
|
||||
const newVal = new BigNumber(value[0])
|
||||
.decimalPlaces(market.positionDecimalPlaces)
|
||||
.toString();
|
||||
const isValid = validateSize(step)(newVal);
|
||||
if (isValid !== 'step') {
|
||||
setValue('size', newVal);
|
||||
}
|
||||
};
|
||||
|
||||
const transactionStatus =
|
||||
transaction.status === VegaTxStatus.Requested ||
|
||||
transaction.status === VegaTxStatus.Pending
|
||||
@@ -112,19 +154,29 @@ export const DealTicketSteps = ({
|
||||
},
|
||||
{
|
||||
label: t('Choose Position Size'),
|
||||
component: (
|
||||
<DealTicketAmount
|
||||
orderType={orderType}
|
||||
step={step}
|
||||
register={register}
|
||||
price={
|
||||
market.depth.lastTrade
|
||||
? addDecimal(market.depth.lastTrade.price, market.decimalPlaces)
|
||||
: undefined
|
||||
}
|
||||
quoteName={market.tradableInstrument.instrument.product.quoteName}
|
||||
/>
|
||||
),
|
||||
component:
|
||||
max !== null ? (
|
||||
<DealTicketSize
|
||||
step={step}
|
||||
min={step}
|
||||
max={max}
|
||||
onValueChange={onSizeChange}
|
||||
value={new BigNumber(orderSize).toNumber()}
|
||||
name="size"
|
||||
price={
|
||||
market.depth.lastTrade
|
||||
? addDecimal(market.depth.lastTrade.price, market.decimalPlaces)
|
||||
: ''
|
||||
}
|
||||
positionDecimalPlaces={market.positionDecimalPlaces}
|
||||
quoteName={market.tradableInstrument.instrument.product.quoteName}
|
||||
estCloseOut={estCloseOut}
|
||||
estMargin={estMargin || ' - '}
|
||||
/>
|
||||
) : (
|
||||
'loading...'
|
||||
),
|
||||
value: orderSize,
|
||||
},
|
||||
{
|
||||
label: t('Review Trade'),
|
||||
@@ -140,12 +192,13 @@ export const DealTicketSteps = ({
|
||||
isDisabled={isDisabled}
|
||||
transactionStatus={transactionStatus}
|
||||
order={order}
|
||||
partyData={partyData}
|
||||
estCloseOut={estCloseOut}
|
||||
estMargin={estMargin || ' - '}
|
||||
/>
|
||||
<TransactionDialog
|
||||
title={getDialogTitle(finalizedOrder?.status)}
|
||||
intent={getDialogIntent(finalizedOrder?.status)}
|
||||
icon={getDialogIcon(finalizedOrder?.status)}
|
||||
title={getOrderDialogTitle(finalizedOrder?.status)}
|
||||
intent={getOrderDialogIntent(finalizedOrder?.status)}
|
||||
icon={getOrderDialogIcon(finalizedOrder?.status)}
|
||||
>
|
||||
<OrderFeedback transaction={transaction} order={finalizedOrder} />
|
||||
</TransactionDialog>
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export { DealTicketContainer } from './deal-ticket-container';
|
||||
export * from './deal-ticket-container';
|
||||
export * from './deal-ticket-size';
|
||||
|
||||
@@ -10,17 +10,14 @@ import classNames from 'classnames';
|
||||
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
import { SIDE_NAMES } from './side-selector';
|
||||
import { useVegaWallet, VegaWalletOrderSide } from '@vegaprotocol/wallet';
|
||||
import { VegaWalletOrderSide } from '@vegaprotocol/wallet';
|
||||
import SimpleMarketExpires from '../simple-market-list/simple-market-expires';
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import type {
|
||||
MarketTags,
|
||||
MarketTagsVariables,
|
||||
} from './__generated__/MarketTags';
|
||||
import useOrderMargin from '../../hooks/use-order-margin';
|
||||
import useOrderCloseOut from '../../hooks/use-order-closeout';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
|
||||
|
||||
export const MARKET_TAGS_QUERY = gql`
|
||||
query MarketTags($marketId: ID!) {
|
||||
@@ -41,7 +38,8 @@ interface Props {
|
||||
isDisabled: boolean;
|
||||
transactionStatus?: string;
|
||||
order: Order;
|
||||
partyData?: PartyBalanceQuery;
|
||||
estCloseOut: string;
|
||||
estMargin: string;
|
||||
}
|
||||
|
||||
export default ({
|
||||
@@ -49,21 +47,16 @@ export default ({
|
||||
market,
|
||||
order,
|
||||
transactionStatus,
|
||||
partyData,
|
||||
estCloseOut,
|
||||
estMargin,
|
||||
}: Props) => {
|
||||
const { keypair } = useVegaWallet();
|
||||
const { data: tagsData } = useQuery<MarketTags, MarketTagsVariables>(
|
||||
MARKET_TAGS_QUERY,
|
||||
{
|
||||
variables: { marketId: market.id },
|
||||
}
|
||||
);
|
||||
const estMargin = useOrderMargin({
|
||||
order,
|
||||
market,
|
||||
partyId: keypair?.pub || '',
|
||||
});
|
||||
const estCloseOut = useOrderCloseOut({ order, market, partyData });
|
||||
|
||||
return (
|
||||
<div className="mb-8 text-black dark:text-white">
|
||||
<KeyValueTable>
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit';
|
||||
import Logo from './logo';
|
||||
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
|
||||
|
||||
type WalletParams = {
|
||||
connect: boolean;
|
||||
manage: boolean;
|
||||
};
|
||||
import LocalContext from '../../context/local-context';
|
||||
|
||||
interface Props {
|
||||
setVegaWallet: (func: (wParams: WalletParams) => WalletParams) => void;
|
||||
toggleTheme: () => void;
|
||||
}
|
||||
const Header = ({ setVegaWallet, toggleTheme }: Props) => {
|
||||
const Header = ({ toggleTheme }: Props) => {
|
||||
const {
|
||||
vegaWalletDialog: { setConnect, setManage },
|
||||
} = useContext(LocalContext);
|
||||
return (
|
||||
<div
|
||||
className="flex items-stretch pr-16 py-16 bg-black text-white-60"
|
||||
@@ -21,12 +19,8 @@ const Header = ({ setVegaWallet, toggleTheme }: Props) => {
|
||||
<Logo />
|
||||
<div className="flex items-center gap-4 ml-auto mr-8 relative z-10">
|
||||
<VegaWalletConnectButton
|
||||
setConnectDialog={(open) =>
|
||||
setVegaWallet((x) => ({ ...x, connect: open }))
|
||||
}
|
||||
setManageDialog={(open) =>
|
||||
setVegaWallet((x) => ({ ...x, manage: open }))
|
||||
}
|
||||
setConnectDialog={setConnect}
|
||||
setManageDialog={setManage}
|
||||
/>
|
||||
<ThemeSwitcher
|
||||
onToggle={toggleTheme}
|
||||
|
||||
@@ -1,13 +1,49 @@
|
||||
import { useContext } from 'react';
|
||||
import { AccountsContainer } from '@vegaprotocol/accounts';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { Button, Splash, Tabs, Tab } from '@vegaprotocol/ui-toolkit';
|
||||
import LocalContext from '../../context/local-context';
|
||||
import { OrderListContainer } from '@vegaprotocol/orders';
|
||||
import { PositionsContainer } from '@vegaprotocol/positions';
|
||||
import { FillsContainer } from '@vegaprotocol/fills';
|
||||
|
||||
export const Portfolio = () => {
|
||||
const { keypair } = useVegaWallet();
|
||||
const {
|
||||
vegaWalletDialog: { setConnect },
|
||||
} = useContext(LocalContext);
|
||||
if (!keypair) {
|
||||
return (
|
||||
<Splash>
|
||||
<div className="text-center">
|
||||
<p className="mb-12" data-testid="connect-vega-wallet-text">
|
||||
{t('Connect your Vega wallet')}
|
||||
</p>
|
||||
<Button
|
||||
onClick={() => setConnect(true)}
|
||||
data-testid="vega-wallet-connect"
|
||||
>
|
||||
{t('Connect')}
|
||||
</Button>
|
||||
</div>
|
||||
</Splash>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<section>
|
||||
<h2 className="text-lg mb-16">{t('Assets')}</h2>
|
||||
<div className="h-screen">
|
||||
<Tabs>
|
||||
<Tab id="assets" name={t('Assets')}>
|
||||
<AccountsContainer />
|
||||
</div>
|
||||
</section>
|
||||
</Tab>
|
||||
<Tab id="positions" name={t('Positions')}>
|
||||
<PositionsContainer />
|
||||
</Tab>
|
||||
<Tab id="orders" name={t('Orders')}>
|
||||
<OrderListContainer />
|
||||
</Tab>
|
||||
<Tab id="fills" name={t('Fills')}>
|
||||
<FillsContainer />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
+3
-1
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import * as React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import {
|
||||
render,
|
||||
@@ -60,6 +60,7 @@ describe('SimpleMarketList', () => {
|
||||
};
|
||||
await act(async () => {
|
||||
render(
|
||||
// @ts-ignore different versions of react types in apollo and app
|
||||
<MockedProvider mocks={[mocks, filterMock]}>
|
||||
<SimpleMarketList />
|
||||
</MockedProvider>,
|
||||
@@ -129,6 +130,7 @@ describe('SimpleMarketList', () => {
|
||||
};
|
||||
await act(async () => {
|
||||
render(
|
||||
// @ts-ignore different versions of react types in apollo and app
|
||||
<MockedProvider mocks={[mocks, filterMock]}>
|
||||
<SimpleMarketList />
|
||||
</MockedProvider>,
|
||||
|
||||
+15
-3
@@ -25,6 +25,14 @@ import SimpleMarketToolbar from './simple-market-toolbar';
|
||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||
import type { SimpleMarketDataSub_marketData } from './__generated__/SimpleMarketDataSub';
|
||||
import { IS_MARKET_TRADABLE } from '../../constants';
|
||||
import type {
|
||||
CellKeyDownEvent,
|
||||
FullWidthCellKeyDownEvent,
|
||||
} from 'ag-grid-community/dist/lib/events';
|
||||
import type {
|
||||
GetRowIdParams,
|
||||
TabToNextCellParams,
|
||||
} from 'ag-grid-community/dist/lib/entities/iCallbackParams';
|
||||
|
||||
export type SimpleMarketsType = SimpleMarkets_markets & {
|
||||
percentChange?: number | '-';
|
||||
@@ -84,7 +92,7 @@ const SimpleMarketList = () => {
|
||||
|
||||
const { columnDefs, defaultColDef } = useColumnDefinitions({ isMobile });
|
||||
|
||||
const getRowId = useCallback(({ data }) => data.id, []);
|
||||
const getRowId = useCallback(({ data }: GetRowIdParams) => data.id, []);
|
||||
|
||||
const handleRowClicked = useCallback(
|
||||
({ data }: { data: SimpleMarketsType }) => {
|
||||
@@ -95,7 +103,7 @@ const SimpleMarketList = () => {
|
||||
[navigate]
|
||||
);
|
||||
|
||||
const onTabToNextCell = useCallback((params) => {
|
||||
const onTabToNextCell = useCallback((params: TabToNextCellParams) => {
|
||||
const {
|
||||
api,
|
||||
previousCellPosition: { rowIndex },
|
||||
@@ -108,7 +116,11 @@ const SimpleMarketList = () => {
|
||||
}, []);
|
||||
|
||||
const onCellKeyDown = useCallback(
|
||||
(params) => {
|
||||
(
|
||||
params: (CellKeyDownEvent | FullWidthCellKeyDownEvent) & {
|
||||
event: KeyboardEvent;
|
||||
}
|
||||
) => {
|
||||
const { event: { key = '' } = {}, data } = params;
|
||||
if (key === 'Enter') {
|
||||
handleRowClicked({ data });
|
||||
|
||||
+60
-50
@@ -7,6 +7,7 @@ import type { MockedResponse } from '@apollo/client/testing';
|
||||
import type { MarketFilters } from './__generated__/MarketFilters';
|
||||
import { FILTERS_QUERY } from './data-provider';
|
||||
import filterData from './mocks/market-filters.json';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
describe('SimpleMarketToolbar', () => {
|
||||
const filterMock: MockedResponse<MarketFilters> = {
|
||||
@@ -58,65 +59,74 @@ describe('SimpleMarketToolbar', () => {
|
||||
});
|
||||
|
||||
it('should be properly rendered', async () => {
|
||||
render(
|
||||
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
||||
<WrappedCompForTest />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Future')).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.click(screen.getByText('Future'));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('market-products-menu').children).toHaveLength(
|
||||
3
|
||||
act(async () => {
|
||||
render(
|
||||
// @ts-ignore different versions of react types in apollo and app
|
||||
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
||||
<WrappedCompForTest />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
expect(screen.getByTestId('market-assets-menu').children).toHaveLength(6);
|
||||
});
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
expect(screen.getByRole('menu').children).toHaveLength(10);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Future')).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.click(screen.getByText('Future'));
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByTestId('market-products-menu').children
|
||||
).toHaveLength(3);
|
||||
expect(screen.getByTestId('market-assets-menu').children).toHaveLength(
|
||||
6
|
||||
);
|
||||
});
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
expect(screen.getByRole('menu').children).toHaveLength(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('navigation should work well', async () => {
|
||||
render(
|
||||
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
||||
<WrappedCompForTest />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Future')).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.click(screen.getByText('Future'));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Active/Future'
|
||||
act(async () => {
|
||||
render(
|
||||
// @ts-ignore different versions of react types in apollo and app
|
||||
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
||||
<WrappedCompForTest />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
});
|
||||
|
||||
fireEvent.click(
|
||||
screen
|
||||
.getByTestId('market-assets-menu')
|
||||
.children[5].querySelector('a') as HTMLAnchorElement
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Active/Future/tEURO'
|
||||
);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Future')).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.click(screen.getByText('Future'));
|
||||
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByText('Pending'));
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Pending/Future/tEURO'
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Active/Future'
|
||||
);
|
||||
});
|
||||
|
||||
fireEvent.click(
|
||||
screen
|
||||
.getByTestId('market-assets-menu')
|
||||
.children[5].querySelector('a') as HTMLAnchorElement
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Active/Future/tEURO'
|
||||
);
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByText('Pending'));
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Pending/Future/tEURO'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export interface VegaWalletDialogState {
|
||||
connect: boolean;
|
||||
manage: boolean;
|
||||
setConnect: (isOpen: boolean) => void;
|
||||
setManage: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
export interface LocalValues {
|
||||
vegaWalletDialog: VegaWalletDialogState;
|
||||
}
|
||||
|
||||
const LocalContext = createContext<LocalValues>({} as LocalValues);
|
||||
|
||||
export default LocalContext;
|
||||
@@ -0,0 +1,52 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: MarketMarkPrice
|
||||
// ====================================================
|
||||
|
||||
export interface MarketMarkPrice_market_data {
|
||||
__typename: "MarketData";
|
||||
/**
|
||||
* the mark price (actually an unsigned int)
|
||||
*/
|
||||
markPrice: string;
|
||||
}
|
||||
|
||||
export interface MarketMarkPrice_market {
|
||||
__typename: "Market";
|
||||
/**
|
||||
* decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct
|
||||
* number denominated in the currency of the Market. (uint64)
|
||||
*
|
||||
* Examples:
|
||||
* Currency Balance decimalPlaces Real Balance
|
||||
* GBP 100 0 GBP 100
|
||||
* GBP 100 2 GBP 1.00
|
||||
* GBP 100 4 GBP 0.01
|
||||
* GBP 1 4 GBP 0.0001 ( 0.01p )
|
||||
*
|
||||
* GBX (pence) 100 0 GBP 1.00 (100p )
|
||||
* GBX (pence) 100 2 GBP 0.01 ( 1p )
|
||||
* GBX (pence) 100 4 GBP 0.0001 ( 0.01p )
|
||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||
*/
|
||||
decimalPlaces: number;
|
||||
/**
|
||||
* marketData for the given market
|
||||
*/
|
||||
data: MarketMarkPrice_market_data | null;
|
||||
}
|
||||
|
||||
export interface MarketMarkPrice {
|
||||
/**
|
||||
* An instrument that is trading on the VEGA network
|
||||
*/
|
||||
market: MarketMarkPrice_market | null;
|
||||
}
|
||||
|
||||
export interface MarketMarkPriceVariables {
|
||||
marketId: string;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AccountType } from "@vegaprotocol/types";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: PartyMarketData
|
||||
// ====================================================
|
||||
|
||||
export interface PartyMarketData_party_accounts_asset {
|
||||
__typename: "Asset";
|
||||
/**
|
||||
* The id of the asset
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The precision of the asset
|
||||
*/
|
||||
decimals: number;
|
||||
}
|
||||
|
||||
export interface PartyMarketData_party_accounts_market {
|
||||
__typename: "Market";
|
||||
/**
|
||||
* Market ID
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface PartyMarketData_party_accounts {
|
||||
__typename: "Account";
|
||||
/**
|
||||
* Account type (General, Margin, etc)
|
||||
*/
|
||||
type: AccountType;
|
||||
/**
|
||||
* Balance as string - current account balance (approx. as balances can be updated several times per second)
|
||||
*/
|
||||
balance: string;
|
||||
/**
|
||||
* Asset, the 'currency'
|
||||
*/
|
||||
asset: PartyMarketData_party_accounts_asset;
|
||||
/**
|
||||
* Market (only relevant to margin accounts)
|
||||
*/
|
||||
market: PartyMarketData_party_accounts_market | null;
|
||||
}
|
||||
|
||||
export interface PartyMarketData_party_marginsConnection_edges_node_market {
|
||||
__typename: "Market";
|
||||
/**
|
||||
* Market ID
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface PartyMarketData_party_marginsConnection_edges_node {
|
||||
__typename: "MarginLevels";
|
||||
/**
|
||||
* market in which the margin is required for this party
|
||||
*/
|
||||
market: PartyMarketData_party_marginsConnection_edges_node_market;
|
||||
/**
|
||||
* this is the minimal margin required for a party to place a new order on the network (unsigned int actually)
|
||||
*/
|
||||
initialLevel: string;
|
||||
/**
|
||||
* minimal margin for the position to be maintained in the network (unsigned int actually)
|
||||
*/
|
||||
maintenanceLevel: string;
|
||||
/**
|
||||
* if the margin is between maintenance and search, the network will initiate a collateral search (unsigned int actually)
|
||||
*/
|
||||
searchLevel: string;
|
||||
}
|
||||
|
||||
export interface PartyMarketData_party_marginsConnection_edges {
|
||||
__typename: "MarginEdge";
|
||||
node: PartyMarketData_party_marginsConnection_edges_node;
|
||||
}
|
||||
|
||||
export interface PartyMarketData_party_marginsConnection {
|
||||
__typename: "MarginConnection";
|
||||
/**
|
||||
* The margin levels in this connection
|
||||
*/
|
||||
edges: PartyMarketData_party_marginsConnection_edges[] | null;
|
||||
}
|
||||
|
||||
export interface PartyMarketData_party {
|
||||
__typename: "Party";
|
||||
/**
|
||||
* Party identifier
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Collateral accounts relating to a party
|
||||
*/
|
||||
accounts: PartyMarketData_party_accounts[] | null;
|
||||
/**
|
||||
* Margin level for a market
|
||||
*/
|
||||
marginsConnection: PartyMarketData_party_marginsConnection;
|
||||
}
|
||||
|
||||
export interface PartyMarketData {
|
||||
/**
|
||||
* An entity that is trading on the VEGA network
|
||||
*/
|
||||
party: PartyMarketData_party | null;
|
||||
}
|
||||
|
||||
export interface PartyMarketDataVariables {
|
||||
partyId: string;
|
||||
}
|
||||
@@ -3,16 +3,46 @@
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AccountType } from "@vegaprotocol/types";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: MarketPositions
|
||||
// ====================================================
|
||||
|
||||
export interface MarketPositions_party_positionsConnection_edges_node_market_accounts {
|
||||
export interface MarketPositions_party_accounts_asset {
|
||||
__typename: "Asset";
|
||||
/**
|
||||
* The precision of the asset
|
||||
*/
|
||||
decimals: number;
|
||||
}
|
||||
|
||||
export interface MarketPositions_party_accounts_market {
|
||||
__typename: "Market";
|
||||
/**
|
||||
* Market ID
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface MarketPositions_party_accounts {
|
||||
__typename: "Account";
|
||||
/**
|
||||
* Account type (General, Margin, etc)
|
||||
*/
|
||||
type: AccountType;
|
||||
/**
|
||||
* Balance as string - current account balance (approx. as balances can be updated several times per second)
|
||||
*/
|
||||
balance: string;
|
||||
/**
|
||||
* Asset, the 'currency'
|
||||
*/
|
||||
asset: MarketPositions_party_accounts_asset;
|
||||
/**
|
||||
* Market (only relevant to margin accounts)
|
||||
*/
|
||||
market: MarketPositions_party_accounts_market | null;
|
||||
}
|
||||
|
||||
export interface MarketPositions_party_positionsConnection_edges_node_market {
|
||||
@@ -21,10 +51,6 @@ export interface MarketPositions_party_positionsConnection_edges_node_market {
|
||||
* Market ID
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Get account for a party or market
|
||||
*/
|
||||
accounts: MarketPositions_party_positionsConnection_edges_node_market_accounts[] | null;
|
||||
}
|
||||
|
||||
export interface MarketPositions_party_positionsConnection_edges_node {
|
||||
@@ -58,6 +84,10 @@ export interface MarketPositions_party {
|
||||
* Party identifier
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Collateral accounts relating to a party
|
||||
*/
|
||||
accounts: MarketPositions_party_accounts[] | null;
|
||||
/**
|
||||
* Trading positions relating to a party
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import useLocalValues from './use-local-values';
|
||||
|
||||
describe('local values hook', () => {
|
||||
it('state of wallet dialog should be properly handled', () => {
|
||||
const { result } = renderHook(() => useLocalValues());
|
||||
expect(result.current.vegaWalletDialog).toBeDefined();
|
||||
expect(result.current.vegaWalletDialog.manage).toBe(false);
|
||||
expect(result.current.vegaWalletDialog.connect).toBe(false);
|
||||
act(() => {
|
||||
result.current.vegaWalletDialog.setConnect(true);
|
||||
result.current.vegaWalletDialog.setManage(true);
|
||||
});
|
||||
expect(result.current.vegaWalletDialog.manage).toBe(true);
|
||||
expect(result.current.vegaWalletDialog.connect).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import type { LocalValues } from '../context/local-context';
|
||||
|
||||
const useLocalValues = () => {
|
||||
const [connect, setConnect] = useState<boolean>(false);
|
||||
const [manage, setManage] = useState<boolean>(false);
|
||||
return useMemo<LocalValues>(
|
||||
() => ({
|
||||
vegaWalletDialog: { connect, manage, setConnect, setManage },
|
||||
}),
|
||||
[connect, manage, setConnect, setManage]
|
||||
);
|
||||
};
|
||||
|
||||
export default useLocalValues;
|
||||
@@ -0,0 +1,38 @@
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import type {
|
||||
MarketMarkPrice,
|
||||
MarketMarkPriceVariables,
|
||||
} from './__generated__/MarketMarkPrice';
|
||||
|
||||
const MARKET_MARK_PRICE = gql`
|
||||
query MarketMarkPrice($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
decimalPlaces
|
||||
data {
|
||||
markPrice
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default (marketId: string) => {
|
||||
const memoRef = useRef<MarketMarkPrice | null>(null);
|
||||
const { data } = useQuery<MarketMarkPrice, MarketMarkPriceVariables>(
|
||||
MARKET_MARK_PRICE,
|
||||
{
|
||||
pollInterval: 5000,
|
||||
variables: { marketId },
|
||||
skip: !marketId,
|
||||
}
|
||||
);
|
||||
return useMemo(() => {
|
||||
if (
|
||||
data &&
|
||||
data.market?.data?.markPrice !== memoRef.current?.market?.data?.markPrice
|
||||
) {
|
||||
memoRef.current = data;
|
||||
}
|
||||
return memoRef.current;
|
||||
}, [data, memoRef]);
|
||||
};
|
||||
@@ -0,0 +1,133 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import useMarketPositions from './use-market-positions';
|
||||
|
||||
let mockNotEmptyData = {
|
||||
party: {
|
||||
accounts: [
|
||||
{
|
||||
balance: '50001000000',
|
||||
asset: {
|
||||
decimals: 5,
|
||||
},
|
||||
market: {
|
||||
id: 'marketId',
|
||||
},
|
||||
},
|
||||
{
|
||||
balance: '700000000000000000000000000000',
|
||||
asset: {
|
||||
decimals: 5,
|
||||
},
|
||||
market: {
|
||||
id: 'someOtherMarketId',
|
||||
},
|
||||
},
|
||||
],
|
||||
positionsConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
openVolume: '100002',
|
||||
market: {
|
||||
id: 'marketId',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
node: {
|
||||
openVolume: '3',
|
||||
market: {
|
||||
id: 'someOtherMarketId',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock('@apollo/client', () => ({
|
||||
...jest.requireActual('@apollo/client'),
|
||||
useQuery: jest.fn(() => ({ data: mockNotEmptyData })),
|
||||
}));
|
||||
|
||||
describe('useOrderPosition Hook', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('should return proper positive value', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useMarketPositions({ marketId: 'marketId', partyId: 'partyId' })
|
||||
);
|
||||
expect(result.current?.openVolume.toNumber()).toEqual(100002);
|
||||
expect(result.current?.balance.toString()).toEqual('50001000000');
|
||||
});
|
||||
|
||||
it('if balance equal 0 return null', () => {
|
||||
mockNotEmptyData = {
|
||||
party: {
|
||||
accounts: [
|
||||
{
|
||||
balance: '0',
|
||||
asset: {
|
||||
decimals: 5,
|
||||
},
|
||||
market: {
|
||||
id: 'marketId',
|
||||
},
|
||||
},
|
||||
],
|
||||
positionsConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
openVolume: '2',
|
||||
market: {
|
||||
id: 'marketId',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
const { result } = renderHook(() =>
|
||||
useMarketPositions({ marketId: 'marketId', partyId: 'partyId' })
|
||||
);
|
||||
expect(result.current).toBeNull();
|
||||
});
|
||||
|
||||
it('if no markets return null', () => {
|
||||
mockNotEmptyData = {
|
||||
party: {
|
||||
accounts: [
|
||||
{
|
||||
balance: '33330',
|
||||
asset: {
|
||||
decimals: 5,
|
||||
},
|
||||
market: {
|
||||
id: 'otherMarketId',
|
||||
},
|
||||
},
|
||||
],
|
||||
positionsConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
openVolume: '2',
|
||||
market: {
|
||||
id: 'otherMarketId',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
const { result } = renderHook(() =>
|
||||
useMarketPositions({ marketId: 'marketId', partyId: 'partyId' })
|
||||
);
|
||||
expect(result.current).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -9,15 +9,22 @@ const MARKET_POSITIONS_QUERY = gql`
|
||||
query MarketPositions($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
id
|
||||
accounts {
|
||||
type
|
||||
balance
|
||||
asset {
|
||||
decimals
|
||||
}
|
||||
market {
|
||||
id
|
||||
}
|
||||
}
|
||||
positionsConnection {
|
||||
edges {
|
||||
node {
|
||||
openVolume
|
||||
market {
|
||||
id
|
||||
accounts {
|
||||
balance
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,40 +38,40 @@ interface Props {
|
||||
partyId: string;
|
||||
}
|
||||
|
||||
type PositionMargin = {
|
||||
export type PositionMargin = {
|
||||
openVolume: BigNumber;
|
||||
balanceSum: BigNumber;
|
||||
balance: BigNumber;
|
||||
balanceDecimals?: number;
|
||||
} | null;
|
||||
|
||||
export default ({ marketId, partyId }: Props): PositionMargin => {
|
||||
const { data } = useQuery<MarketPositions, MarketPositionsVariables>(
|
||||
MARKET_POSITIONS_QUERY,
|
||||
{
|
||||
pollInterval: 15000,
|
||||
pollInterval: 5000,
|
||||
variables: { partyId },
|
||||
skip: !partyId,
|
||||
}
|
||||
);
|
||||
|
||||
const markets =
|
||||
data?.party?.positionsConnection?.edges
|
||||
?.filter((nodes) => nodes.node.market.id === marketId)
|
||||
.map((nodes) => nodes.node) || [];
|
||||
const account = data?.party?.accounts?.find(
|
||||
(nodes) => nodes.market?.id === marketId
|
||||
);
|
||||
|
||||
return markets.length
|
||||
? markets.reduce(
|
||||
(agg, item) => {
|
||||
const balance = item.market.accounts?.reduce(
|
||||
(acagg, account) => acagg.plus(account.balance || 0),
|
||||
new BigNumber(0)
|
||||
);
|
||||
if (balance) {
|
||||
agg.balanceSum = agg.balanceSum.plus(balance);
|
||||
agg.openVolume = agg.openVolume.plus(item.openVolume);
|
||||
}
|
||||
return agg;
|
||||
},
|
||||
{ openVolume: new BigNumber(0), balanceSum: new BigNumber(0) }
|
||||
)
|
||||
: null;
|
||||
if (account) {
|
||||
const balance = new BigNumber(account.balance || 0);
|
||||
const openVolume = new BigNumber(
|
||||
data?.party?.positionsConnection?.edges?.find(
|
||||
(nodes) => nodes.node.market.id === marketId
|
||||
)?.node.openVolume || 0
|
||||
);
|
||||
if (!balance.isZero() && !openVolume.isZero()) {
|
||||
return {
|
||||
balance,
|
||||
balanceDecimals: account?.asset.decimals,
|
||||
openVolume,
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import useMaximumPositionSize from './use-maximum-position-size';
|
||||
import type { PartyBalanceQuery_party_accounts } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
import type { PositionMargin } from './use-market-positions';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import {
|
||||
VegaWalletOrderSide,
|
||||
VegaWalletOrderTimeInForce,
|
||||
VegaWalletOrderType,
|
||||
} from '@vegaprotocol/wallet';
|
||||
|
||||
const defaultMockMarketPositions = {
|
||||
openVolume: new BigNumber(1),
|
||||
balance: new BigNumber(100000),
|
||||
};
|
||||
|
||||
let mockMarketPositions: PositionMargin | null = defaultMockMarketPositions;
|
||||
|
||||
const mockAccount: PartyBalanceQuery_party_accounts = {
|
||||
__typename: 'Account',
|
||||
type: AccountType.General,
|
||||
balance: '200000',
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'tBTC',
|
||||
name: 'tBTC TEST',
|
||||
decimals: 5,
|
||||
},
|
||||
};
|
||||
|
||||
const mockOrder = {
|
||||
type: VegaWalletOrderType.Market,
|
||||
size: '1',
|
||||
side: VegaWalletOrderSide.Buy,
|
||||
timeInForce: VegaWalletOrderTimeInForce.IOC,
|
||||
};
|
||||
|
||||
jest.mock('./use-settlement-account', () => {
|
||||
return {
|
||||
useSettlementAccount: jest.fn(() => mockAccount),
|
||||
};
|
||||
});
|
||||
jest.mock('./use-market-positions', () => jest.fn(() => mockMarketPositions));
|
||||
|
||||
describe('useMaximumPositionSize Hook', () => {
|
||||
it('should return correct size when no open positions', () => {
|
||||
mockMarketPositions = null;
|
||||
const price = '50';
|
||||
const expected = 4000;
|
||||
const { result } = renderHook(() =>
|
||||
useMaximumPositionSize({
|
||||
marketId: '',
|
||||
partyId: '',
|
||||
price,
|
||||
settlementAssetId: '',
|
||||
order: mockOrder,
|
||||
accounts: [mockAccount],
|
||||
})
|
||||
);
|
||||
expect(result.current).toBe(expected);
|
||||
});
|
||||
|
||||
it('should return correct size when open positions and same side', () => {
|
||||
const price = '50';
|
||||
mockMarketPositions = defaultMockMarketPositions;
|
||||
const expected = 3999;
|
||||
const { result } = renderHook(() =>
|
||||
useMaximumPositionSize({
|
||||
marketId: '',
|
||||
partyId: '',
|
||||
price,
|
||||
settlementAssetId: '',
|
||||
order: mockOrder,
|
||||
accounts: [mockAccount],
|
||||
})
|
||||
);
|
||||
expect(result.current).toBe(expected);
|
||||
});
|
||||
|
||||
it('should return correct size when open positions and opposite side', () => {
|
||||
const price = '50';
|
||||
mockOrder.side = VegaWalletOrderSide.Sell;
|
||||
mockMarketPositions = defaultMockMarketPositions;
|
||||
const expected = 4001;
|
||||
const { result } = renderHook(() =>
|
||||
useMaximumPositionSize({
|
||||
marketId: '',
|
||||
partyId: '',
|
||||
price,
|
||||
settlementAssetId: '',
|
||||
order: mockOrder,
|
||||
accounts: [mockAccount],
|
||||
})
|
||||
);
|
||||
expect(result.current).toBe(expected);
|
||||
});
|
||||
|
||||
it('should return zero if no account balance', () => {
|
||||
mockAccount.balance = '0';
|
||||
const price = '50';
|
||||
mockMarketPositions = defaultMockMarketPositions;
|
||||
const expected = 0;
|
||||
const { result } = renderHook(() =>
|
||||
useMaximumPositionSize({
|
||||
marketId: '',
|
||||
partyId: '',
|
||||
price,
|
||||
settlementAssetId: '',
|
||||
order: mockOrder,
|
||||
accounts: [],
|
||||
})
|
||||
);
|
||||
expect(result.current).toBe(expected);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import useMarketPositions from './use-market-positions';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
import type { PartyBalanceQuery_party_accounts } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
||||
import { useSettlementAccount } from './use-settlement-account';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
import { VegaWalletOrderSide } from '@vegaprotocol/wallet';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
|
||||
interface Props {
|
||||
partyId: string;
|
||||
accounts: PartyBalanceQuery_party_accounts[];
|
||||
marketId: string;
|
||||
price?: string;
|
||||
settlementAssetId: string;
|
||||
order: Order;
|
||||
}
|
||||
|
||||
const getSize = (balance: string, price: string) =>
|
||||
new BigNumber(balance).dividedBy(new BigNumber(price));
|
||||
|
||||
export default ({
|
||||
marketId,
|
||||
accounts,
|
||||
partyId,
|
||||
price,
|
||||
settlementAssetId,
|
||||
order,
|
||||
}: Props): number => {
|
||||
const settlementAccount = useSettlementAccount(
|
||||
settlementAssetId,
|
||||
accounts,
|
||||
AccountType.General
|
||||
);
|
||||
|
||||
const marketPositions = useMarketPositions({ marketId: marketId, partyId });
|
||||
|
||||
if (
|
||||
!settlementAccount?.balance ||
|
||||
new BigNumber(settlementAccount?.balance || 0).isZero()
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const size = getSize(settlementAccount.balance, price || '');
|
||||
|
||||
if (!marketPositions) {
|
||||
return size.toNumber() || 0;
|
||||
}
|
||||
|
||||
const isSameSide =
|
||||
(marketPositions.openVolume.isPositive() &&
|
||||
order.side === VegaWalletOrderSide.Buy) ||
|
||||
(marketPositions.openVolume.isNegative() &&
|
||||
order.side === VegaWalletOrderSide.Sell);
|
||||
|
||||
const adjustedForVolume = new BigNumber(size)[isSameSide ? 'minus' : 'plus'](
|
||||
marketPositions.openVolume
|
||||
);
|
||||
|
||||
return adjustedForVolume.isNegative() ? 0 : adjustedForVolume.toNumber();
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
import * as React from 'react';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import useOrderCloseOut from './use-order-closeout';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
||||
import type { PartyBalanceQuery } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
||||
|
||||
jest.mock('@vegaprotocol/wallet', () => ({
|
||||
...jest.requireActual('@vegaprotocol/wallet'),
|
||||
useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'),
|
||||
}));
|
||||
|
||||
describe('useOrderCloseOut Hook', () => {
|
||||
const order = { size: '2', side: 'SIDE_BUY' };
|
||||
const market = {
|
||||
decimalPlaces: 5,
|
||||
depth: {
|
||||
lastTrade: {
|
||||
price: '1000000',
|
||||
},
|
||||
},
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
product: {
|
||||
settlementAsset: {
|
||||
id: 'assetId',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const partyData = {
|
||||
party: {
|
||||
accounts: [
|
||||
{
|
||||
balance: '200000',
|
||||
asset: {
|
||||
id: 'assetId',
|
||||
decimals: 5,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
it('return proper buy value', () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useOrderCloseOut({
|
||||
order: order as Order,
|
||||
market: market as DealTicketQuery_market,
|
||||
partyData: partyData as PartyBalanceQuery,
|
||||
}),
|
||||
{
|
||||
wrapper: ({ children }: { children: React.ReactNode }) => (
|
||||
// @ts-ignore different versions of react types in apollo and app
|
||||
<MockedProvider mocks={[]}>{children}</MockedProvider>
|
||||
),
|
||||
}
|
||||
);
|
||||
expect(result.current).toEqual(' - ');
|
||||
});
|
||||
|
||||
it('return proper sell value', () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useOrderCloseOut({
|
||||
order: { ...order, side: 'SIDE_SELL' } as Order,
|
||||
market: market as DealTicketQuery_market,
|
||||
partyData: partyData as PartyBalanceQuery,
|
||||
}),
|
||||
{
|
||||
wrapper: ({ children }: { children: React.ReactNode }) => (
|
||||
// @ts-ignore different versions of react types in apollo and app
|
||||
<MockedProvider mocks={[]}>{children}</MockedProvider>
|
||||
),
|
||||
}
|
||||
);
|
||||
expect(result.current).toEqual('1.00000');
|
||||
});
|
||||
|
||||
it('return proper empty value', () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useOrderCloseOut({
|
||||
order: { ...order, side: 'SIDE_SELL' } as Order,
|
||||
market: market as DealTicketQuery_market,
|
||||
}),
|
||||
{
|
||||
wrapper: ({ children }: { children: React.ReactNode }) => (
|
||||
// @ts-ignore different versions of react types in apollo and app
|
||||
<MockedProvider mocks={[]}>{children}</MockedProvider>
|
||||
),
|
||||
}
|
||||
);
|
||||
expect(result.current).toEqual('0.00000');
|
||||
});
|
||||
});
|
||||
@@ -3,8 +3,46 @@ import type { Order } from '@vegaprotocol/orders';
|
||||
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
||||
import type { PartyBalanceQuery } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
||||
import { useSettlementAccount } from './use-settlement-account';
|
||||
import { VegaWalletOrderSide } from '@vegaprotocol/wallet';
|
||||
import { useVegaWallet, VegaWalletOrderSide } from '@vegaprotocol/wallet';
|
||||
import { addDecimal, formatNumber } from '@vegaprotocol/react-helpers';
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import useMarketPositions from './use-market-positions';
|
||||
import useMarketData from './use-market-data';
|
||||
import type {
|
||||
PartyMarketData,
|
||||
PartyMarketDataVariables,
|
||||
} from './__generated__/PartyMarketData';
|
||||
|
||||
const CLOSEOUT_PRICE_QUERY = gql`
|
||||
query PartyMarketData($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
id
|
||||
accounts {
|
||||
type
|
||||
balance
|
||||
asset {
|
||||
id
|
||||
decimals
|
||||
}
|
||||
market {
|
||||
id
|
||||
}
|
||||
}
|
||||
marginsConnection {
|
||||
edges {
|
||||
node {
|
||||
market {
|
||||
id
|
||||
}
|
||||
initialLevel
|
||||
maintenanceLevel
|
||||
searchLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
order: Order;
|
||||
@@ -13,25 +51,65 @@ interface Props {
|
||||
}
|
||||
|
||||
const useOrderCloseOut = ({ order, market, partyData }: Props): string => {
|
||||
const { keypair } = useVegaWallet();
|
||||
const account = useSettlementAccount(
|
||||
market.tradableInstrument.instrument.product.settlementAsset.id,
|
||||
partyData?.party?.accounts || []
|
||||
);
|
||||
if (account?.balance && market.depth.lastTrade) {
|
||||
const price = new BigNumber(
|
||||
addDecimal(market.depth.lastTrade.price, market.decimalPlaces)
|
||||
);
|
||||
const balance = new BigNumber(
|
||||
addDecimal(account.balance, account.asset.decimals)
|
||||
);
|
||||
const { size, side } = order;
|
||||
const bigOne = new BigNumber(1);
|
||||
return formatNumber(
|
||||
side === VegaWalletOrderSide.Buy
|
||||
? bigOne.minus(balance.div(price.times(size))).times(price)
|
||||
: bigOne.plus(balance.div(price.times(size))).times(price),
|
||||
const { data } = useQuery<PartyMarketData, PartyMarketDataVariables>(
|
||||
CLOSEOUT_PRICE_QUERY,
|
||||
{
|
||||
pollInterval: 5000,
|
||||
variables: { partyId: keypair?.pub || '' },
|
||||
skip: !keypair?.pub,
|
||||
}
|
||||
);
|
||||
|
||||
const markPriceData = useMarketData(market.id);
|
||||
const marketPositions = useMarketPositions({
|
||||
marketId: market.id,
|
||||
partyId: keypair?.pub || '',
|
||||
});
|
||||
|
||||
const marginMaintenanceLevel = new BigNumber(
|
||||
addDecimal(
|
||||
data?.party?.marginsConnection.edges?.find(
|
||||
(nodes) => nodes.node.market.id === market.id
|
||||
)?.node.maintenanceLevel || 0,
|
||||
market.decimalPlaces
|
||||
);
|
||||
)
|
||||
);
|
||||
const positionAccount = data?.party?.accounts?.find(
|
||||
(account) => account.market?.id === market.id
|
||||
);
|
||||
const positionAccountBalance = new BigNumber(
|
||||
addDecimal(
|
||||
positionAccount?.balance || 0,
|
||||
positionAccount?.asset?.decimals || 0
|
||||
)
|
||||
);
|
||||
const generalAccountBalance = new BigNumber(
|
||||
addDecimal(account?.balance || 0, account?.asset.decimals || 0)
|
||||
);
|
||||
const volume = new BigNumber(
|
||||
addDecimal(
|
||||
marketPositions?.openVolume.toNumber() || 0,
|
||||
market.positionDecimalPlaces
|
||||
)
|
||||
)[order.side === VegaWalletOrderSide.Buy ? 'plus' : 'minus'](order.size);
|
||||
const markPrice = new BigNumber(
|
||||
addDecimal(
|
||||
markPriceData?.market?.data?.markPrice || 0,
|
||||
markPriceData?.market?.decimalPlaces || 0
|
||||
)
|
||||
);
|
||||
// regarding formula (marginMaintenanceLevel - positionAccountBalance - generalAccountBalance) / volume + markPrice
|
||||
const marginDifference = marginMaintenanceLevel
|
||||
.minus(positionAccountBalance)
|
||||
.minus(generalAccountBalance);
|
||||
const closeOut = marginDifference.div(volume).plus(markPrice);
|
||||
if (closeOut.isPositive()) {
|
||||
return formatNumber(closeOut, market.decimalPlaces);
|
||||
}
|
||||
return ' - ';
|
||||
};
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
||||
import type { PositionMargin } from './use-market-positions';
|
||||
import useOrderMargin from './use-order-margin';
|
||||
|
||||
let mockEstimateData = {
|
||||
estimateOrder: {
|
||||
marginLevels: {
|
||||
initialLevel: '200000',
|
||||
},
|
||||
},
|
||||
};
|
||||
jest.mock('@apollo/client', () => ({
|
||||
...jest.requireActual('@apollo/client'),
|
||||
useQuery: jest.fn(() => ({ data: mockEstimateData })),
|
||||
}));
|
||||
|
||||
let mockMarketPositions: PositionMargin = {
|
||||
openVolume: new BigNumber(1),
|
||||
balance: new BigNumber(100000),
|
||||
};
|
||||
jest.mock('./use-market-positions', () => jest.fn(() => mockMarketPositions));
|
||||
|
||||
describe('useOrderMargin Hook', () => {
|
||||
const order = {
|
||||
size: '2',
|
||||
side: 'SIDE_BUY',
|
||||
timeInForce: 'TIME_IN_FORCE_IOC',
|
||||
type: 'TYPE_MARKET',
|
||||
};
|
||||
const market = {
|
||||
id: 'marketId',
|
||||
depth: {
|
||||
lastTrade: {
|
||||
price: '1000000',
|
||||
},
|
||||
},
|
||||
};
|
||||
const partyId = 'partyId';
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('margin should be properly calculated', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useOrderMargin({
|
||||
order: order as Order,
|
||||
market: market as DealTicketQuery_market,
|
||||
partyId,
|
||||
})
|
||||
);
|
||||
expect(result.current).toEqual('100000');
|
||||
|
||||
const calledSize = new BigNumber(mockMarketPositions?.openVolume || 0)
|
||||
.plus(order.size)
|
||||
.toString();
|
||||
expect((useQuery as jest.Mock).mock.calls[1][1].variables.size).toEqual(
|
||||
calledSize
|
||||
);
|
||||
});
|
||||
|
||||
it('if there is no positions initialMargin should not be subtracted', () => {
|
||||
mockMarketPositions = null;
|
||||
const { result } = renderHook(() =>
|
||||
useOrderMargin({
|
||||
order: order as Order,
|
||||
market: market as DealTicketQuery_market,
|
||||
partyId,
|
||||
})
|
||||
);
|
||||
expect(result.current).toEqual('200000');
|
||||
|
||||
expect((useQuery as jest.Mock).mock.calls[1][1].variables.size).toEqual(
|
||||
order.size
|
||||
);
|
||||
});
|
||||
|
||||
it('if api fails, should return empty value', () => {
|
||||
mockEstimateData = {
|
||||
estimateOrder: {
|
||||
marginLevels: {
|
||||
initialLevel: '',
|
||||
},
|
||||
},
|
||||
};
|
||||
const { result } = renderHook(() =>
|
||||
useOrderMargin({
|
||||
order: order as Order,
|
||||
market: market as DealTicketQuery_market,
|
||||
partyId,
|
||||
})
|
||||
);
|
||||
expect(result.current).toEqual(' - ');
|
||||
|
||||
const calledSize = new BigNumber(mockMarketPositions?.openVolume || 0)
|
||||
.plus(order.size)
|
||||
.toString();
|
||||
expect((useQuery as jest.Mock).mock.calls[1][1].variables.size).toEqual(
|
||||
calledSize
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import type {
|
||||
@@ -11,9 +12,9 @@ import {
|
||||
VegaWalletOrderTimeInForce,
|
||||
VegaWalletOrderType,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import { addDecimal, formatNumber } from '@vegaprotocol/react-helpers';
|
||||
import { addDecimal, removeDecimal } from '@vegaprotocol/react-helpers';
|
||||
import useMarketPositions from './use-market-positions';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import useMarketData from './use-market-data';
|
||||
|
||||
export const ESTIMATE_ORDER_QUERY = gql`
|
||||
query EstimateOrder(
|
||||
@@ -66,43 +67,43 @@ const types: Record<VegaWalletOrderType, OrderType> = {
|
||||
|
||||
const useOrderMargin = ({ order, market, partyId }: Props) => {
|
||||
const marketPositions = useMarketPositions({ marketId: market.id, partyId });
|
||||
console.log('marketPositions', marketPositions);
|
||||
console.log(
|
||||
'marketPositions.openVolume',
|
||||
marketPositions?.openVolume.toNumber()
|
||||
);
|
||||
console.log(
|
||||
'marketPositions.balanceSum',
|
||||
marketPositions?.balanceSum.toNumber()
|
||||
);
|
||||
const markPriceData = useMarketData(market.id);
|
||||
const { data } = useQuery<EstimateOrder, EstimateOrderVariables>(
|
||||
ESTIMATE_ORDER_QUERY,
|
||||
{
|
||||
variables: {
|
||||
marketId: market.id,
|
||||
partyId,
|
||||
price: market.depth.lastTrade?.price,
|
||||
size: order.size + (marketPositions?.openVolume.toNumber() || 0),
|
||||
price: markPriceData?.market?.data?.markPrice || '',
|
||||
size: removeDecimal(
|
||||
BigNumber.maximum(
|
||||
0,
|
||||
new BigNumber(marketPositions?.openVolume || 0)[
|
||||
order.side === VegaWalletOrderSide.Buy ? 'plus' : 'minus'
|
||||
](order.size)
|
||||
).toString(),
|
||||
market.positionDecimalPlaces
|
||||
),
|
||||
side: order.side === VegaWalletOrderSide.Buy ? Side.Buy : Side.Sell,
|
||||
timeInForce: times[order.timeInForce],
|
||||
type: types[order.type],
|
||||
},
|
||||
skip: !partyId || !market.id || !order.size,
|
||||
skip:
|
||||
!partyId ||
|
||||
!market.id ||
|
||||
!order.size ||
|
||||
!markPriceData?.market?.data?.markPrice,
|
||||
}
|
||||
);
|
||||
|
||||
if (data?.estimateOrder.marginLevels.initialLevel) {
|
||||
return formatNumber(
|
||||
Math.max(
|
||||
return addDecimal(
|
||||
BigNumber.maximum(
|
||||
0,
|
||||
new BigNumber(
|
||||
addDecimal(
|
||||
data.estimateOrder.marginLevels.initialLevel,
|
||||
market.decimalPlaces
|
||||
)
|
||||
new BigNumber(data.estimateOrder.marginLevels.initialLevel).minus(
|
||||
marketPositions?.balance || 0
|
||||
)
|
||||
.minus(marketPositions?.balanceSum.toNumber() || 0)
|
||||
.toNumber()
|
||||
),
|
||||
).toString(),
|
||||
market.decimalPlaces
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useSettlementAccount } from './use-settlement-account';
|
||||
import type { PartyBalanceQuery_party_accounts } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
|
||||
describe('useSettlementAccount Hook', () => {
|
||||
it('should filter accounts by settlementAssetId', () => {
|
||||
const accounts: PartyBalanceQuery_party_accounts[] = [
|
||||
{
|
||||
__typename: 'Account',
|
||||
type: AccountType.General,
|
||||
balance: '2000000000000000000000',
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
@@ -18,6 +20,7 @@ describe('useSettlementAccount Hook', () => {
|
||||
},
|
||||
{
|
||||
__typename: 'Account',
|
||||
type: AccountType.General,
|
||||
balance: '1000000000',
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
@@ -29,6 +32,19 @@ describe('useSettlementAccount Hook', () => {
|
||||
},
|
||||
{
|
||||
__typename: 'Account',
|
||||
type: AccountType.General,
|
||||
balance: '5000000000000000000',
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55',
|
||||
symbol: 'VEGA',
|
||||
name: 'Vega (testnet)',
|
||||
decimals: 18,
|
||||
},
|
||||
},
|
||||
{
|
||||
__typename: 'Account',
|
||||
type: AccountType.Margin,
|
||||
balance: '5000000000000000000',
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
@@ -39,14 +55,23 @@ describe('useSettlementAccount Hook', () => {
|
||||
},
|
||||
},
|
||||
];
|
||||
const settlementAssetId =
|
||||
const tDAI =
|
||||
'6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61';
|
||||
const vega =
|
||||
'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55';
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useSettlementAccount(settlementAssetId, accounts)
|
||||
const { result: resultDai } = renderHook(() =>
|
||||
useSettlementAccount(tDAI, accounts)
|
||||
);
|
||||
expect(result.current?.balance).toBe(accounts[1].balance);
|
||||
expect(result.current?.asset).toEqual(accounts[1].asset);
|
||||
expect(resultDai.current?.balance).toBe(accounts[1].balance);
|
||||
expect(resultDai.current?.asset).toEqual(accounts[1].asset);
|
||||
|
||||
const { result: resultVega } = renderHook(() =>
|
||||
useSettlementAccount(vega, accounts, AccountType.Margin)
|
||||
);
|
||||
|
||||
expect(resultVega.current?.balance).toBe(accounts[3].balance);
|
||||
expect(resultVega.current?.asset).toEqual(accounts[3].asset);
|
||||
});
|
||||
|
||||
it('should return null if no accounts', () => {
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
import type { PartyBalanceQuery_party_accounts } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
||||
import type { AccountType } from '@vegaprotocol/types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useSettlementAccount = (
|
||||
settlementAssetId: string,
|
||||
accounts: PartyBalanceQuery_party_accounts[]
|
||||
accounts: PartyBalanceQuery_party_accounts[],
|
||||
type?: AccountType
|
||||
): PartyBalanceQuery_party_accounts | null => {
|
||||
const callback = () =>
|
||||
accounts.find((account) => account.asset.id === settlementAssetId);
|
||||
const account = useMemo(callback, [accounts, settlementAssetId]);
|
||||
accounts.find((account) => {
|
||||
if (type) {
|
||||
return account.asset.id === settlementAssetId && account.type === type;
|
||||
}
|
||||
|
||||
return account.asset.id === settlementAssetId;
|
||||
});
|
||||
const account = useMemo(callback, [accounts, settlementAssetId, type]);
|
||||
return account as PartyBalanceQuery_party_accounts;
|
||||
};
|
||||
|
||||
@@ -23,6 +23,9 @@ export function createClient(base?: string) {
|
||||
|
||||
const cache = new InMemoryCache({
|
||||
typePolicies: {
|
||||
Party: {
|
||||
keyFields: false,
|
||||
},
|
||||
Query: {},
|
||||
Account: {
|
||||
keyFields: false,
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { StrictMode } from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
import App from './app/app';
|
||||
const rootElement = document.getElementById('root');
|
||||
const root = rootElement && createRoot(rootElement);
|
||||
|
||||
ReactDOM.render(
|
||||
root?.render(
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</StrictMode>,
|
||||
document.getElementById('root')
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node", "@testing-library/jest-dom"],
|
||||
"jsx": "react"
|
||||
"jsx": "react",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": [
|
||||
"**/*.test.ts",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@
|
||||
"tranche_end": "2022-11-26T13:48:10.000Z",
|
||||
"total_added": "100",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "33.170119863013703",
|
||||
"locked_amount": "29.334677828513445",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "100",
|
||||
@@ -242,7 +242,7 @@
|
||||
"tranche_end": "2022-10-12T00:53:20.000Z",
|
||||
"total_added": "1100",
|
||||
"total_removed": "673.04388635",
|
||||
"locked_amount": "227.633273084728555",
|
||||
"locked_amount": "185.443410705225717",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1000",
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
"tranche_end": "2022-10-12T00:53:20.000Z",
|
||||
"total_added": "1010.000000000000000001",
|
||||
"total_removed": "668.4622323651",
|
||||
"locked_amount": "209.00876458650434070020693937087772707",
|
||||
"locked_amount": "170.27076801116179470016858491882293247",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1000",
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import React, { StrictMode } from 'react';
|
||||
import './styles/styles.css';
|
||||
import App from './app';
|
||||
import reportWebVitals from './report-web-vitals';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
const rootElement = document.getElementById('root');
|
||||
const root = rootElement && createRoot(rootElement);
|
||||
|
||||
root?.render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
|
||||
@@ -3,7 +3,6 @@ NX_VEGA_ENV=TESTNET
|
||||
NX_ETHEREUM_PROVIDER_URL=http://localhost:8545
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
NX_FAIRGROUND=false
|
||||
NX_IS_NEW_BRIDGE_CONTRACT=true
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET":"https://dev.token.vega.xyz","STAGNET2":"staging2.token.vega.xyz","TESTNET":"token.fairground.wtf","MAINNET":"token.vega.xyz"}'
|
||||
|
||||
NX_VEGA_URL=http://localhost:3028/query
|
||||
|
||||
@@ -40,5 +40,7 @@ module.exports = defineConfig({
|
||||
vegaWalletPublicKeyShort: '02ecea…2f65',
|
||||
vegaTokenContractAddress: '0xF41bD86d462D36b997C0bbb4D97a0a3382f205B7',
|
||||
vegaTokenAddress: '0x67175Da1D5e966e40D11c4B2519392B2058373de',
|
||||
epochTimeout: { timeout: 10000 },
|
||||
txTimeout: { timeout: 40000 },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// <reference types="cypress" />
|
||||
const stakeValidatorList = '[data-testid="node-list-item-name"]';
|
||||
const stakeValidatorWithinList = '[data-testid="node-list-item"]';
|
||||
const stakeValidatorListTotalStake = '[col-id="totalStakeThisEpoch"]';
|
||||
const stakeValidatorListTotalShare = '[col-id="share"]';
|
||||
const stakeValidatorListValidatorStake = '[col-id="validatorStake"]';
|
||||
const stakeRemoveStakeRadioButton = '[data-testid="remove-stake-radio"]';
|
||||
const stakeTokenAmountInputBox = '[data-testid="token-amount-input"]';
|
||||
const stakeTokenSubmitButton = '[data-testid="token-input-submit-button"]';
|
||||
@@ -8,6 +9,8 @@ const stakeNextEpochValue = '[data-testid="stake-next-epoch"]';
|
||||
const stakeThisEpochValue = '[data-testid="stake-this-epoch"]';
|
||||
const stakeAddStakeRadioButton = '[data-testid="add-stake-radio"]';
|
||||
const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]';
|
||||
const totalStake = '[data-testid="total-stake"]';
|
||||
const stakeShare = '[data-testid="stake-percentage"]';
|
||||
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
|
||||
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
||||
const vegaWalletUnstakedBalance =
|
||||
@@ -22,11 +25,12 @@ const ethWalletAssociatedBalances =
|
||||
'[data-testid="eth-wallet-associated-balances"]';
|
||||
const ethWalletTotalAssociatedBalance = '[data-testid="currency-locked"]';
|
||||
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
|
||||
const txTimeout = { timeout: 40000 };
|
||||
const epochTimeout = { timeout: 10000 };
|
||||
const partValidatorId = '…';
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
const epochTimeout = Cypress.env('epochTimeout');
|
||||
|
||||
// Tests skipped because of change of the UI of data nodes
|
||||
context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
context('Staking Tab - with eth and vega wallets connected', function () {
|
||||
// 1002-STKE-002, 1002-STKE-032
|
||||
before('visit staking tab and connect vega wallet', function () {
|
||||
cy.vega_wallet_import();
|
||||
cy.visit('/');
|
||||
@@ -38,8 +42,6 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
cy.ethereum_wallet_connect();
|
||||
cy.navigate_to('staking');
|
||||
cy.wait_for_spinner();
|
||||
cy.get(stakeValidatorList).first().invoke('text').as('validatorName');
|
||||
cy.get(stakeValidatorList).last().invoke('text').as('otherValidatorName');
|
||||
});
|
||||
|
||||
describe('Eth wallet - contains VEGA tokens', function () {
|
||||
@@ -48,9 +50,11 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
function () {
|
||||
cy.vega_wallet_teardown();
|
||||
cy.navigate_to('staking');
|
||||
cy.wait_for_spinner();
|
||||
}
|
||||
);
|
||||
|
||||
// 1002-STKE-004
|
||||
it('Able to stake against a validator', function () {
|
||||
cy.staking_page_associate_tokens('3');
|
||||
|
||||
@@ -71,13 +75,16 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
// 1002-STKE-031
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
// 1002-STKE-033, 1002-STKE-034, 1002-STKE-037
|
||||
cy.staking_validator_page_add_stake('2');
|
||||
|
||||
// 1002-STKE-038
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout)
|
||||
.should('contain', 2.0, txTimeout)
|
||||
.and('contain', this.validatorName)
|
||||
.and('contain', partValidatorId)
|
||||
.and('contain', 'Next epoch');
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
@@ -86,30 +93,25 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
txTimeout
|
||||
);
|
||||
|
||||
// 1002-STKE-039
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
.should('contain', 2.0, txTimeout)
|
||||
.and('contain', this.validatorName);
|
||||
.and('contain', partValidatorId);
|
||||
|
||||
cy.get(stakeNextEpochValue, epochTimeout)
|
||||
cy.get(stakeNextEpochValue, epochTimeout) // 1002-STKE-016
|
||||
.contains(2.0, epochTimeout)
|
||||
.should('be.visible');
|
||||
|
||||
cy.get(stakeThisEpochValue, epochTimeout)
|
||||
cy.get(stakeThisEpochValue, epochTimeout) // 1002-STKE-013
|
||||
.contains(2.0, epochTimeout)
|
||||
.should('be.visible');
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
cy.get(stakeValidatorWithinList, epochTimeout)
|
||||
.contains(this.validatorName)
|
||||
.parent()
|
||||
.contains('Total stake')
|
||||
.parent()
|
||||
.should('contain', '2.0')
|
||||
.and('contain', '100%');
|
||||
cy.validate_validator_list_total_stake_and_share('0', '', '2.00', '100%');
|
||||
});
|
||||
|
||||
it('Able to stake against mulitple validators', function () {
|
||||
it('Able to stake against multiple validators', function () {
|
||||
cy.staking_page_associate_tokens('5');
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
@@ -119,30 +121,29 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
);
|
||||
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
cy.staking_validator_page_add_stake('2');
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
.contains(this.validatorName, txTimeout)
|
||||
.parent()
|
||||
.should('contain', 2.0, txTimeout);
|
||||
|
||||
cy.navigate_to('staking');
|
||||
cy.get(stakeValidatorList).contains(this.otherValidatorName).click();
|
||||
|
||||
cy.click_on_validator_from_list(1);
|
||||
|
||||
cy.staking_validator_page_add_stake('1');
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
.should('have.length', 2, txTimeout)
|
||||
.contains(this.otherValidatorName, txTimeout)
|
||||
.parent()
|
||||
.should('contain', 1.0, txTimeout);
|
||||
.eq(0)
|
||||
.should('contain', 2.0, txTimeout);
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
.contains(this.validatorName, txTimeout)
|
||||
.parent()
|
||||
.should('contain', 2.0, txTimeout);
|
||||
.eq(1)
|
||||
.should('contain', 1.0, txTimeout);
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
@@ -152,23 +153,35 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
cy.get(stakeValidatorWithinList, epochTimeout)
|
||||
.contains(this.validatorName)
|
||||
.parent()
|
||||
.contains('Total stake')
|
||||
.parent()
|
||||
.should('contain', '2.0')
|
||||
.and('contain', '66.67%');
|
||||
cy.get(`[row-id="${0}"]`).within(() => {
|
||||
cy.get(stakeValidatorListTotalStake)
|
||||
.should('have.text', '2.00')
|
||||
.and('be.visible');
|
||||
cy.get(stakeValidatorListTotalShare)
|
||||
.should('have.text', '66.67%')
|
||||
.and('be.visible');
|
||||
cy.get(stakeValidatorListValidatorStake)
|
||||
.scrollIntoView()
|
||||
.should('have.text', '2.00')
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
cy.get(stakeValidatorWithinList, epochTimeout)
|
||||
.contains(this.otherValidatorName)
|
||||
.parent()
|
||||
.contains('Total stake')
|
||||
.parent()
|
||||
.should('contain', '1.0')
|
||||
.and('contain', '33.33%');
|
||||
cy.get(`[row-id="${1}"]`).within(() => {
|
||||
cy.get(stakeValidatorListTotalStake)
|
||||
.scrollIntoView()
|
||||
.should('have.text', '1.00')
|
||||
.and('be.visible');
|
||||
cy.get(stakeValidatorListTotalShare)
|
||||
.should('have.text', '33.33%')
|
||||
.and('be.visible');
|
||||
cy.get(stakeValidatorListValidatorStake)
|
||||
.scrollIntoView()
|
||||
.should('have.text', '1.00')
|
||||
.and('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
// 1002-STKE-041
|
||||
it('Able to remove part of a stake against a validator', function () {
|
||||
cy.staking_page_associate_tokens('4');
|
||||
|
||||
@@ -179,7 +192,8 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
);
|
||||
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
cy.staking_validator_page_add_stake('3');
|
||||
|
||||
@@ -187,10 +201,11 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
.contains(3.0, epochTimeout)
|
||||
.should('be.visible');
|
||||
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout)
|
||||
.should('contain', 3.0, txTimeout)
|
||||
.and('contain', this.validatorName)
|
||||
.and('contain', 'Next epoch');
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout).should(
|
||||
'contain',
|
||||
3.0,
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
@@ -199,22 +214,24 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
);
|
||||
|
||||
cy.navigate_to('staking');
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
// 1002-STKE-040
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
// 1002-STKE-044, 1002-STKE-048
|
||||
cy.staking_validator_page_remove_stake('1');
|
||||
|
||||
cy.get(stakeNextEpochValue, epochTimeout)
|
||||
.contains(2.0, epochTimeout)
|
||||
.should('be.visible');
|
||||
// 1002-STKE-049
|
||||
cy.get(stakeNextEpochValue, epochTimeout).contains(2.0, epochTimeout);
|
||||
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout)
|
||||
.should('contain', 2.0, txTimeout)
|
||||
.and('contain', this.validatorName)
|
||||
.and('contain', 'Next epoch');
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout).should(
|
||||
'contain',
|
||||
2.0,
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.get(vegaWalletThisEpochBalances, txTimeout)
|
||||
.should('contain', 3.0, txTimeout)
|
||||
.and('contain', this.validatorName)
|
||||
.and('contain', partValidatorId)
|
||||
.and('contain', 'This Epoch');
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
@@ -223,9 +240,11 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
.should('contain', 2.0, txTimeout)
|
||||
.and('contain', this.validatorName);
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
||||
'contain',
|
||||
2.0,
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.get(stakeNextEpochValue, epochTimeout)
|
||||
.contains(2.0, epochTimeout)
|
||||
@@ -235,15 +254,13 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
.contains(2.0, epochTimeout)
|
||||
.should('be.visible');
|
||||
|
||||
cy.get(totalStake).should('have.text', '2');
|
||||
|
||||
cy.get(stakeShare).should('have.text', '100%');
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
cy.get(stakeValidatorWithinList, epochTimeout)
|
||||
.contains(this.validatorName)
|
||||
.parent()
|
||||
.contains('Total stake')
|
||||
.parent()
|
||||
.should('contain', '2.0')
|
||||
.and('contain', '100%');
|
||||
cy.validate_validator_list_total_stake_and_share('0', '', '2.00', '100%');
|
||||
});
|
||||
|
||||
it('Able to remove a full stake against a validator', function () {
|
||||
@@ -257,14 +274,15 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
cy.staking_validator_page_add_stake('1');
|
||||
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout)
|
||||
.should('contain', 1.0, txTimeout)
|
||||
.and('contain', this.validatorName)
|
||||
.and('contain', 'Next epoch');
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout).should(
|
||||
'contain',
|
||||
1.0,
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
@@ -274,7 +292,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
cy.click_on_validator_from_list('0');
|
||||
|
||||
cy.staking_validator_page_remove_stake('1');
|
||||
|
||||
@@ -282,15 +300,17 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
.contains(0.0, epochTimeout)
|
||||
.should('be.visible');
|
||||
|
||||
cy.get(vegaWalletThisEpochBalances, txTimeout)
|
||||
.should('contain', 1.0, txTimeout)
|
||||
.and('contain', this.validatorName)
|
||||
.and('contain', 'This Epoch');
|
||||
cy.get(vegaWalletThisEpochBalances, txTimeout).should(
|
||||
'contain',
|
||||
1.0,
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout)
|
||||
.should('contain', 0.0, txTimeout)
|
||||
.and('contain', this.validatorName)
|
||||
.and('contain', 'Next epoch');
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout).should(
|
||||
'contain',
|
||||
0.0,
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
@@ -307,17 +327,12 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
.should('be.visible');
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
.contains(this.validatorName, txTimeout)
|
||||
.contains(partValidatorId, txTimeout)
|
||||
.should('not.exist', txTimeout);
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
cy.get(stakeValidatorWithinList, epochTimeout)
|
||||
.contains(this.validatorName)
|
||||
.parent()
|
||||
.contains('Total stake')
|
||||
.parent()
|
||||
.should('contain', '0.0');
|
||||
cy.validate_validator_list_total_stake_and_share('0', '', '0.00', '-');
|
||||
});
|
||||
|
||||
it('Unable to remove a stake with a negative value for a validator', function () {
|
||||
@@ -331,7 +346,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
cy.staking_validator_page_add_stake('2');
|
||||
|
||||
@@ -339,10 +354,11 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
.contains(2.0, epochTimeout)
|
||||
.should('be.visible');
|
||||
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout)
|
||||
.should('contain', 2.0, txTimeout)
|
||||
.and('contain', this.validatorName)
|
||||
.and('contain', 'Next epoch');
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout).should(
|
||||
'contain',
|
||||
2.0,
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
@@ -352,9 +368,9 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
cy.get(stakeRemoveStakeRadioButton).click({ force: true });
|
||||
cy.get(stakeRemoveStakeRadioButton, txTimeout).click();
|
||||
|
||||
cy.get(stakeTokenAmountInputBox).type('-0.1');
|
||||
|
||||
@@ -377,7 +393,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
cy.staking_validator_page_add_stake('2');
|
||||
|
||||
@@ -387,8 +403,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.get(vegaWalletNextEpochBalances, txTimeout)
|
||||
.should('contain', 2.0, txTimeout)
|
||||
.and('contain', this.validatorName)
|
||||
.and('contain', 'Next epoch');
|
||||
.and('contain', partValidatorId);
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
@@ -398,9 +413,9 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
cy.get(stakeRemoveStakeRadioButton).click({ force: true });
|
||||
cy.get(stakeRemoveStakeRadioButton).click();
|
||||
|
||||
cy.get(stakeTokenAmountInputBox).type(4);
|
||||
|
||||
@@ -412,7 +427,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
it.skip('Disassociating all tokens max - removes all staked tokens', function () {
|
||||
it('Disassociating all tokens max - removes all staked tokens', function () {
|
||||
cy.staking_page_associate_tokens('3');
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
@@ -423,7 +438,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
cy.click_on_validator_from_list('1');
|
||||
|
||||
cy.staking_validator_page_add_stake('2');
|
||||
|
||||
@@ -433,9 +448,11 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
.should('contain', 2.0, txTimeout)
|
||||
.and('contain', this.validatorName);
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
||||
'contain',
|
||||
2.0,
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
@@ -457,18 +474,14 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
.contains(this.validatorName, txTimeout)
|
||||
.should('not.exist', txTimeout);
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
||||
'not.exist',
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
cy.get(stakeValidatorWithinList, epochTimeout)
|
||||
.contains(this.validatorName)
|
||||
.parent()
|
||||
.contains('Total stake')
|
||||
.parent()
|
||||
.should('contain', '0.0');
|
||||
cy.validate_validator_list_total_stake_and_share('0', '', '0.00', '-');
|
||||
});
|
||||
|
||||
it('Disassociating some tokens - prioritizes unstaked tokens', function () {
|
||||
@@ -481,7 +494,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
);
|
||||
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
cy.staking_validator_page_add_stake('2');
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
@@ -490,9 +503,11 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
.should('contain', 2.0, txTimeout)
|
||||
.and('contain', this.validatorName);
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
||||
'contain',
|
||||
2.0,
|
||||
txTimeout
|
||||
);
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
@@ -510,20 +525,14 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
||||
.should('contain', 2.0, txTimeout)
|
||||
.and('contain', this.validatorName);
|
||||
.and('contain', partValidatorId);
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
cy.get(stakeValidatorWithinList, epochTimeout)
|
||||
.contains(this.validatorName)
|
||||
.parent()
|
||||
.contains('Total stake')
|
||||
.parent()
|
||||
.should('contain', '2.0')
|
||||
.and('contain', '100%');
|
||||
cy.validate_validator_list_total_stake_and_share('0', '', '2.00', '100%');
|
||||
});
|
||||
|
||||
it('Selecting use maximum where tokens are allready staked - suggests the unstaked token amount', function () {
|
||||
it('Selecting use maximum where tokens are already staked - suggests the unstaked token amount', function () {
|
||||
cy.staking_page_associate_tokens('3');
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
@@ -533,7 +542,7 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
);
|
||||
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
cy.get(stakeValidatorList).contains(this.validatorName).click();
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
cy.staking_validator_page_add_stake('2');
|
||||
|
||||
@@ -545,9 +554,9 @@ context.skip('Staking Tab - with eth and vega wallets connected', function () {
|
||||
|
||||
cy.navigate_to('staking');
|
||||
|
||||
cy.get(stakeValidatorList).contains(this.otherValidatorName).click();
|
||||
cy.click_on_validator_from_list(0);
|
||||
|
||||
cy.get(stakeAddStakeRadioButton).click({ force: true });
|
||||
cy.get(stakeAddStakeRadioButton).click();
|
||||
|
||||
cy.get(stakeMaximumTokens, { timeout: 60000 }).click();
|
||||
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
/// <reference types="cypress" />
|
||||
const guideLink = '[data-testid="staking-guide-link"]';
|
||||
const validators = '[data-testid="validators-grid"]';
|
||||
const validatorTitle = '[data-testid="validator-node-title"]';
|
||||
const validatorId = '[data-testid="validator-id"]';
|
||||
const validatorPubKey = '[data-testid="validator-public-key"]';
|
||||
const ethAddressLink = '[data-testid="link"]';
|
||||
const totalStake = '[data-testid="total-stake"]';
|
||||
const pendingStake = '[data-testid="pending-stake"]';
|
||||
const stakedByOperator = '[data-testid="staked-by-operator"]';
|
||||
const stakedByDelegates = '[data-testid="staked-by-delegates"]';
|
||||
const stakeShare = '[data-testid="stake-percentage"]';
|
||||
const epochCountDown = '[data-testid="epoch-countdown"]';
|
||||
const stakeNumberRegex = /^\d*\.?\d*$/;
|
||||
const ownStake = '[data-testid="own-stake"]';
|
||||
const nominatedStake = '[data-testid="nominated-stake"]';
|
||||
|
||||
context('Staking Page - verify elements on page', function () {
|
||||
before('navigate to staking page', function () {
|
||||
@@ -17,6 +30,7 @@ context('Staking Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
it('should have Staking Guide link visible', function () {
|
||||
// 1002-STKE-003
|
||||
cy.get(guideLink)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Read more about staking on Vega')
|
||||
@@ -27,9 +41,168 @@ context('Staking Page - verify elements on page', function () {
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('validators section', function () {
|
||||
it('should be visible', function () {
|
||||
cy.get(validators).should('be.visible');
|
||||
|
||||
describe('Should be able to see validator list from the staking page', function () {
|
||||
// 1002-STKE-050
|
||||
it('Should be able to see validator names', function () {
|
||||
cy.get('[col-id="validator"]')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($name) => {
|
||||
cy.wrap($name).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator status', function () {
|
||||
cy.get('[col-id="status"]')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($status) => {
|
||||
cy.wrap($status).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see total stake for this epoch', function () {
|
||||
cy.get('[col-id="totalStakeThisEpoch"]')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($totalStaked) => {
|
||||
cy.wrap($totalStaked).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator staked for this epoch', function () {
|
||||
cy.get('[col-id="validatorStake"]')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($validatorStake) => {
|
||||
cy.wrap($validatorStake).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator staked for next epoch', function () {
|
||||
cy.get('[col-id="pendingStake"]')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($pendingStake) => {
|
||||
cy.wrap($pendingStake).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
// 1002-STKE-021
|
||||
it('Should be able to see validator ranking score', function () {
|
||||
cy.get('.ag-body-horizontal-scroll-viewport').scrollTo('right');
|
||||
cy.get('[col-id="rankingScore"]')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($rankingScore) => {
|
||||
cy.wrap($rankingScore).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
// 1002-STKE-022
|
||||
it('Should be able to see validator stake score', function () {
|
||||
cy.get('[col-id="stakeScore"]')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($stakeScore) => {
|
||||
cy.wrap($stakeScore).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
// 1002-STKE-023
|
||||
it('Should be able to see validator performance score', function () {
|
||||
cy.get('[col-id="performanceScore"]')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($performanceScore) => {
|
||||
cy.wrap($performanceScore).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
// 1002-STKE-024
|
||||
it('Should be able to see validator voting power score', function () {
|
||||
cy.get('[col-id="votingPower"]')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($votingPower) => {
|
||||
cy.wrap($votingPower).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 1002-STKE-050
|
||||
describe('Should be able to see static information about a validator', function () {
|
||||
before('connect wallets and click on validator', function () {
|
||||
cy.vega_wallet_import();
|
||||
cy.vega_wallet_connect();
|
||||
cy.click_on_validator_from_list(0);
|
||||
});
|
||||
|
||||
// 1002-STKE-005
|
||||
it('Should be able to see validator name', function () {
|
||||
cy.get(validatorTitle).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 1002-STKE-007
|
||||
it('Should be able to see validator id', function () {
|
||||
cy.get(validatorId).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 1002-STKE-008
|
||||
it('Should be able to see validator public key', function () {
|
||||
cy.get(validatorPubKey).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 1002-STKE-010
|
||||
it('Should be able to see Ethereum address', function () {
|
||||
cy.get(ethAddressLink).should('not.be.empty').and('have.attr', 'href');
|
||||
});
|
||||
// TODO validators missing url for more information about them 1002-STKE-09
|
||||
|
||||
// 1002-STKE-012
|
||||
it('Should be able to see total stake', function () {
|
||||
cy.get(totalStake).invoke('text').should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see pending stake', function () {
|
||||
cy.get(pendingStake).invoke('text').should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see staked by operator', function () {
|
||||
cy.get(stakedByOperator).invoke('text').should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see staked by delegates', function () {
|
||||
cy.get(stakedByDelegates)
|
||||
.invoke('text')
|
||||
.should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
// 1002-STKE-051
|
||||
it('Should be able to see stake share in percentage', function () {
|
||||
cy.get(stakeShare)
|
||||
.invoke('text')
|
||||
.then(($stakePercentage) => {
|
||||
if ($stakePercentage != '-') {
|
||||
cy.wrap($stakePercentage).should(
|
||||
'match',
|
||||
/\b(?<!\.)(?!0+(?:\.0+)?%)(?:\d|[1-9]\d|100)(?:(?<!100)\.\d+)?%/
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 1002-STKE-013
|
||||
it('Should be able to see own stake this epoch', function () {
|
||||
cy.get(ownStake).invoke('text').should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
// 1002-STKE-014
|
||||
it('Should be able to see nominated stake this epoch', function () {
|
||||
cy.get(nominatedStake).invoke('text').should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
// 1002-STKE-011
|
||||
it('should be able to see epoch information', function () {
|
||||
const epochTitle = 'h3';
|
||||
const nextEpochInfo = 'p';
|
||||
|
||||
cy.get(epochCountDown).within(() => {
|
||||
cy.get(epochTitle).should('not.be.empty');
|
||||
cy.get(nextEpochInfo).should('contain.text', 'Next epoch');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ const navigation = {
|
||||
rewards: '[href="/rewards"]',
|
||||
withdraw: '[href="/withdraw"]',
|
||||
governance: '[href="/governance"]',
|
||||
pageSpinner: 'splash-loader',
|
||||
pageSpinner: '[data-testid="splash-loader"]',
|
||||
};
|
||||
|
||||
Cypress.Commands.add('navigate_to', (page) => {
|
||||
|
||||
@@ -7,6 +7,11 @@ const ethWalletAssociateButton = '[href="/staking/associate"]';
|
||||
const ethWalletDissociateButton = '[href="/staking/disassociate"]';
|
||||
const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
|
||||
const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]';
|
||||
const stakeValidatorListPendingStake = '[col-id="pendingStake"]';
|
||||
const stakeValidatorListTotalStake = '[col-id="totalStakeThisEpoch"]';
|
||||
const stakeValidatorListTotalShare = '[col-id="share"]';
|
||||
const stakeValidatorListName = '[col-id="validator"]';
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
|
||||
Cypress.Commands.add('wait_for_begining_of_epoch', () => {
|
||||
cy.contains('Waiting for next epoch to start', { timeout: 10000 }).should(
|
||||
@@ -17,7 +22,7 @@ Cypress.Commands.add('wait_for_begining_of_epoch', () => {
|
||||
|
||||
Cypress.Commands.add('staking_validator_page_add_stake', (stake) => {
|
||||
cy.highlight(`Adding a stake of ${stake}`);
|
||||
cy.get(addStakeRadioButton).click({ force: true });
|
||||
cy.get(addStakeRadioButton, { timeout: 8000 }).click({ force: true });
|
||||
cy.get(tokenAmountInputBox).type(stake);
|
||||
cy.wait_for_begining_of_epoch();
|
||||
cy.get(tokenSubmitButton, { timeout: 8000 })
|
||||
@@ -29,7 +34,7 @@ Cypress.Commands.add('staking_validator_page_add_stake', (stake) => {
|
||||
|
||||
Cypress.Commands.add('staking_validator_page_remove_stake', (stake) => {
|
||||
cy.highlight(`Removing a stake of ${stake}`);
|
||||
cy.get(removeStakeRadioButton).click({ force: true });
|
||||
cy.get(removeStakeRadioButton, { timeout: 8000 }).click();
|
||||
cy.get(tokenAmountInputBox).type(stake);
|
||||
cy.wait_for_begining_of_epoch();
|
||||
cy.get(tokenSubmitButton)
|
||||
@@ -47,9 +52,7 @@ Cypress.Commands.add(
|
||||
cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
|
||||
cy.get(tokenAmountInputBox, { timeout: 10000 }).type(amount);
|
||||
if (approve) {
|
||||
cy.get(tokenInputApprove, { timeout: 40000 })
|
||||
.should('be.enabled')
|
||||
.click();
|
||||
cy.get(tokenInputApprove, txTimeout).should('be.enabled').click();
|
||||
cy.contains('Approve $VEGA Tokens for staking on Vega').should(
|
||||
'be.visible'
|
||||
);
|
||||
@@ -57,7 +60,7 @@ Cypress.Commands.add(
|
||||
timeout: 40000,
|
||||
}).should('not.exist');
|
||||
}
|
||||
cy.get(tokenSubmitButton, { timeout: 40000 }).should('be.enabled').click();
|
||||
cy.get(tokenSubmitButton, txTimeout).should('be.enabled').click();
|
||||
cy.contains('can now participate in governance and nominate a validator', {
|
||||
timeout: 60000,
|
||||
}).should('be.visible');
|
||||
@@ -70,7 +73,7 @@ Cypress.Commands.add('staking_page_disassociate_tokens', (amount) => {
|
||||
cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
|
||||
cy.get(tokenAmountInputBox, { timeout: 10000 }).type(amount);
|
||||
|
||||
cy.get(tokenSubmitButton, { timeout: 40000 }).should('be.enabled').click();
|
||||
cy.get(tokenSubmitButton, txTimeout).should('be.enabled').click();
|
||||
cy.contains(`${amount} $VEGA tokens have been returned to Ethereum wallet`, {
|
||||
timeout: 60000,
|
||||
}).should('be.visible');
|
||||
@@ -86,3 +89,45 @@ Cypress.Commands.add('staking_page_disassociate_all_tokens', () => {
|
||||
timeout: 60000,
|
||||
}).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
'click_on_validator_from_list',
|
||||
(validatorNumber, validatorName = null) => {
|
||||
cy.contains('Waiting for next epoch to start').should('not.exist');
|
||||
// below is to ensure validator list is shown
|
||||
cy.get(stakeValidatorListName, { timeout: 10000 }).should('exist');
|
||||
cy.get(stakeValidatorListPendingStake, txTimeout).should(
|
||||
'not.contain',
|
||||
'2,000,000,000,000,000,000.00' // number due to bug #936
|
||||
);
|
||||
if (validatorName) {
|
||||
cy.contains(validatorName).click();
|
||||
} else {
|
||||
cy.get(`[row-id="${validatorNumber}"]`)
|
||||
.find(stakeValidatorListName)
|
||||
.click();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Cypress.Commands.add(
|
||||
'validate_validator_list_total_stake_and_share',
|
||||
(
|
||||
positionOnList,
|
||||
expectedValidatorName,
|
||||
expectedTotalStake,
|
||||
expectedTotalShare
|
||||
) => {
|
||||
cy.get(`[row-id="${positionOnList}"]`).within(() => {
|
||||
cy.get(stakeValidatorListName).should('have.text', expectedValidatorName);
|
||||
cy.get(stakeValidatorListTotalStake).should(
|
||||
'have.text',
|
||||
expectedTotalStake
|
||||
);
|
||||
cy.get(stakeValidatorListTotalShare).should(
|
||||
'have.text',
|
||||
expectedTotalShare
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
} from '@vegaprotocol/smart-contracts';
|
||||
import { ethers, Wallet } from 'ethers';
|
||||
|
||||
const vegaWalletContainer = '[data-testid="vega-wallet"]';
|
||||
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
||||
const vegaWalletMnemonic = Cypress.env('vegaWalletMnemonic');
|
||||
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey');
|
||||
@@ -40,14 +41,24 @@ before('Vega wallet teardown prep', function () {
|
||||
});
|
||||
|
||||
Cypress.Commands.add('vega_wallet_teardown', function () {
|
||||
cy.vega_wallet_teardown_staking(this.stakingBridgeContract);
|
||||
cy.vega_wallet_teardown_vesting(this.vestingContract);
|
||||
cy.get(vegaWalletContainer).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance)
|
||||
.invoke('text')
|
||||
.then((balance) => {
|
||||
if (balance != '0.000000000000000000') {
|
||||
cy.vega_wallet_teardown_staking(this.stakingBridgeContract);
|
||||
cy.vega_wallet_teardown_vesting(this.vestingContract);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
cy.get(vegaWalletAssociatedBalance, { timeout: transactionTimeout }).should(
|
||||
'contain',
|
||||
'0.000000000000000000',
|
||||
{ timeout: transactionTimeout }
|
||||
);
|
||||
cy.get(vegaWalletContainer).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, { timeout: transactionTimeout }).should(
|
||||
'contain',
|
||||
'0.000000000000000000',
|
||||
{ timeout: transactionTimeout }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
|
||||
@@ -5,7 +5,6 @@ NX_VEGA_URL=https://lb.testnet.vega.xyz/query
|
||||
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
NX_FAIRGROUND=false
|
||||
NX_IS_NEW_BRIDGE_CONTRACT=true
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET":"https://dev.token.vega.xyz","STAGNET2":"staging2.token.vega.xyz","TESTNET":"token.fairground.wtf","MAINNET":"token.vega.xyz"}'
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789/api/v1
|
||||
|
||||
@@ -3,7 +3,6 @@ NX_VEGA_ENV=TESTNET
|
||||
NX_ETHEREUM_PROVIDER_URL=http://localhost:8545
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
NX_FAIRGROUND=false
|
||||
NX_IS_NEW_BRIDGE_CONTRACT=true
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET":"https://dev.token.vega.xyz","STAGNET2":"staging2.token.vega.xyz","TESTNET":"token.fairground.wtf","MAINNET":"token.vega.xyz"}'
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
|
||||
|
||||
@@ -8,4 +8,7 @@ module.exports = {
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/apps/token',
|
||||
setupFilesAfterEnv: ['./src/setup-tests.ts'],
|
||||
moduleNameMapper: {
|
||||
'^d3-(.*)$': `d3-$1/dist/d3-$1`,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ import vegaVesting from '../../images/vega_vesting.png';
|
||||
import vegaWhite from '../../images/vega_white.png';
|
||||
import { BigNumber } from '../../lib/bignumber';
|
||||
import { truncateMiddle } from '../../lib/truncate-middle';
|
||||
import { Routes } from '../../routes/router-config';
|
||||
import Routes from '../../routes/routes';
|
||||
import { LockedProgress } from '../locked-progress';
|
||||
import {
|
||||
WalletCard,
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
export interface HeadingProps {
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface HeadingProps {
|
||||
title?: string;
|
||||
centerContent?: boolean;
|
||||
}
|
||||
|
||||
export const Heading = ({ title }: HeadingProps) => {
|
||||
export const Heading = ({ title, centerContent = true }: HeadingProps) => {
|
||||
if (!title) return null;
|
||||
|
||||
return (
|
||||
<header className="my-0 mx-auto">
|
||||
<header
|
||||
className={classNames('my-0', {
|
||||
'mx-auto': centerContent,
|
||||
})}
|
||||
>
|
||||
<h1 className="font-alpha calt">{title}</h1>
|
||||
</header>
|
||||
);
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
} from '../../contexts/app-state/app-state-context';
|
||||
import { Routes } from '../../routes/router-config';
|
||||
import Routes from '../../routes/routes';
|
||||
import { EthWallet } from '../eth-wallet';
|
||||
import { VegaWallet } from '../vega-wallet';
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export const SplashLoader = ({ text = 'Loading' }: { text?: string }) => {
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div>{text}</div>
|
||||
<div className="text-white">{text}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import vegaWhite from '../../images/vega_white.png';
|
||||
import { BigNumber } from '../../lib/bignumber';
|
||||
import { truncateMiddle } from '../../lib/truncate-middle';
|
||||
import { Routes } from '../../routes/router-config';
|
||||
import Routes from '../../routes/routes';
|
||||
import { BulletHeader } from '../bullet-header';
|
||||
import type { WalletCardAssetProps } from '../wallet-card';
|
||||
import {
|
||||
|
||||
@@ -62,6 +62,9 @@ export const Web3Content = ({ children, appChainId }: Web3ContentProps) => {
|
||||
if (connector?.connectEagerly) {
|
||||
connector.connectEagerly();
|
||||
}
|
||||
// wallet connect doesnt handle connectEagerly being called when connector is also in the
|
||||
// deps array.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [connector]);
|
||||
|
||||
if (error) {
|
||||
|
||||
@@ -66,9 +66,6 @@ export const ENV = {
|
||||
MOCK: TRUTHY.includes(windowOrDefault('NX_MOCKED')),
|
||||
FAIRGROUND: TRUTHY.includes(windowOrDefault('NX_FAIRGROUND')),
|
||||
NETWORK_LIMITS: TRUTHY.includes(windowOrDefault('NX_NETWORK_LIMITS')),
|
||||
USE_NEW_BRIDGE_CONTRACT: TRUTHY.includes(
|
||||
process.env['NX_IS_NEW_BRIDGE_CONTRACT'] as string
|
||||
),
|
||||
},
|
||||
addresses:
|
||||
ContractAddresses[(envName === 'local' ? 'CUSTOM' : envName) as Networks],
|
||||
|
||||
@@ -17,5 +17,9 @@ export const NetworkParams = {
|
||||
'governance.proposal.updateNetParam.requiredMajority',
|
||||
GOV_UPDATE_NET_PARAM_REQUIRED_PARTICIPATION:
|
||||
'governance.proposal.updateNetParam.requiredParticipation',
|
||||
GOV_FREEFORM_REQUIRED_PARTICIPATION:
|
||||
'governance.proposal.freeform.requiredParticipation',
|
||||
GOV_FREEFORM_REQUIRED_MAJORITY:
|
||||
'governance.proposal.freeform.requiredMajority',
|
||||
VALIDATOR_DELEGATION_MIN_AMOUNT: 'validators.delegation.minAmount',
|
||||
};
|
||||
|
||||
@@ -30,6 +30,7 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
|
||||
// contracts so that we can sign transactions, otherwise use the provider for just
|
||||
// reading data
|
||||
React.useEffect(() => {
|
||||
let cancelled = false;
|
||||
const run = async () => {
|
||||
let signer = null;
|
||||
|
||||
@@ -38,7 +39,6 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
|
||||
ETHEREUM_PROVIDER_URL,
|
||||
Number(config.chain_id)
|
||||
);
|
||||
|
||||
const provider = activeProvider ? activeProvider : defaultProvider;
|
||||
|
||||
if (
|
||||
@@ -55,23 +55,28 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
|
||||
signer || provider
|
||||
);
|
||||
const vegaAddress = await staking.staking_token();
|
||||
|
||||
setContracts({
|
||||
token: new Token(vegaAddress, signer || provider),
|
||||
staking: new StakingBridge(
|
||||
config.staking_bridge_contract.address,
|
||||
signer || provider
|
||||
),
|
||||
vesting: new TokenVesting(
|
||||
config.token_vesting_contract.address,
|
||||
signer || provider
|
||||
),
|
||||
claim: new Claim(ENV.addresses.claimAddress, signer || provider),
|
||||
});
|
||||
if (!cancelled) {
|
||||
setContracts({
|
||||
token: new Token(vegaAddress, signer || provider),
|
||||
staking: new StakingBridge(
|
||||
config.staking_bridge_contract.address,
|
||||
signer || provider
|
||||
),
|
||||
vesting: new TokenVesting(
|
||||
config.token_vesting_contract.address,
|
||||
signer || provider
|
||||
),
|
||||
claim: new Claim(ENV.addresses.claimAddress, signer || provider),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
run();
|
||||
return () => {
|
||||
// TODO: hacky quick fix for release to prevent race condition, find a better fix for this.
|
||||
cancelled = true;
|
||||
};
|
||||
}, [activeProvider, account, config, VEGA_ENV, ETHEREUM_PROVIDER_URL]);
|
||||
|
||||
if (!contracts) {
|
||||
|
||||
@@ -157,6 +157,9 @@
|
||||
"Once unlocked they can be redeemed from the contract so that you can transfer them between wallets.": "Once unlocked they can be redeemed from the contract so that you can transfer them between wallets.",
|
||||
"Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.": "Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.",
|
||||
"proposals": "Proposals",
|
||||
"proposal": "Proposal",
|
||||
"submitting": "Submitting",
|
||||
"submit": "Submit",
|
||||
"proposedEnactment": "Proposed enactment",
|
||||
"Enacted": "Enacted",
|
||||
"enactedOn": "Enacted on",
|
||||
@@ -620,5 +623,8 @@
|
||||
"InvalidAssetDetails": "Invalid asset details",
|
||||
"FilterProposals": "Filter proposals",
|
||||
"FilterProposalsDescription": "Filter by proposal ID or proposer ID",
|
||||
"Freeform proposal": "Freeform proposal"
|
||||
"Freeform proposal": "Freeform proposal",
|
||||
"NewProposal": "New proposal",
|
||||
"MinProposalRequirements": "You must have at least 1 VEGA associated to make a proposal",
|
||||
"totalSupply": "Total Supply"
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ import './styles.css';
|
||||
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { Integrations } from '@sentry/tracing';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import App from './app';
|
||||
import reportWebVitals from './report-web-vitals';
|
||||
import { ENV } from './config/env';
|
||||
import { StrictMode } from 'react';
|
||||
|
||||
const dsn = ENV.dsn || false;
|
||||
const environment = ENV.envName || 'local';
|
||||
@@ -38,11 +38,13 @@ if (dsn) {
|
||||
Sentry.setTag('commit', commit);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
const rootElement = document.getElementById('root');
|
||||
const root = rootElement && createRoot(rootElement);
|
||||
|
||||
root?.render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
|
||||
@@ -5,3 +5,8 @@
|
||||
*/
|
||||
import 'core-js/stable';
|
||||
import 'regenerator-runtime/runtime';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
window.Buffer = require('buffer/').Buffer;
|
||||
// eslint-disable-next-line no-undef, no-global-assign, no-native-reassign
|
||||
window.global = globalThis;
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
TransactionActionType,
|
||||
TxState,
|
||||
} from '../../../hooks/transaction-reducer';
|
||||
import { Routes } from '../../router-config';
|
||||
import Routes from '../../routes';
|
||||
|
||||
export interface ICountry {
|
||||
name: string;
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Link as RouteLink } from 'react-router-dom';
|
||||
|
||||
import type { BigNumber } from '../../lib/bignumber';
|
||||
import { formatNumber } from '../../lib/format-number';
|
||||
import { Routes } from '../router-config';
|
||||
import Routes from '../routes';
|
||||
|
||||
export const Complete = ({
|
||||
address,
|
||||
|
||||
@@ -29,7 +29,7 @@ const ClaimIndex = ({ name }: RouteChildProps) => {
|
||||
if (error) {
|
||||
return (
|
||||
<Callout intent={Intent.Danger} title={t('errorLoadingTranches')}>
|
||||
{error}
|
||||
{error.message}
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user