Compare commits

..
Author SHA1 Message Date
Dariusz Majcherczyk 5017224fcd test: update live e2e tests 2023-03-29 14:52:12 +02:00
128 changed files with 968 additions and 2195 deletions
+4 -32
View File
@@ -18,7 +18,6 @@ jobs:
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
# We need to fetch all branches and commits so that Nx affected has a base to compare against.
fetch-depth: 0
- name: Check node version
@@ -34,9 +33,10 @@ jobs:
# Check SHAs
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v3
uses: nrwl/nx-set-shas@v2
with:
main-branch-name: develop
main-branch-name: ${{ github.base_ref || github.ref_name }}
set-environment-variables-for-job: true
# See affected apps
- name: See affected apps
@@ -44,36 +44,8 @@ jobs:
nx_version=$(cat package.json | grep '"nx"' | cut -d ':' -f 2 | tr -d '",[:space:]')
rm package.json yarn.lock
yarn add nx@$nx_version
echo ">>>> debug"
echo "NX Version: $nx_version"
echo "NX_BASE: ${{ env.NX_BASE }}"
echo "NX_HEAD: ${{ env.NX_HEAD }}"
# echo "Main branch name: ${{ github.base_ref || github.ref_name }}"
# echo "git rev-parse HEAD: $(git rev-parse HEAD)"
# echo "Head: ${{ github.head_ref }}"
# echo "command to execute: 'yarn nx print-affected --base=${{ github.base_ref || github.ref_name }} --head=${{ github.head_ref }} --select=projects'"
# merge_base=$(git merge-base origin/develop HEAD)
# echo "git merge-base origin/develop HEAD: $merge_base"
# head_sha="${{ github.event.pull_request.head.sha || github.sha }}"
# echo "Head SHA: $head_sha"
# echo "command to execute (without nx-set-sha): 'yarn nx print-affected --base=$merge_base --head=$head_sha --select=projects'"
echo ">>>> eof debug"
# affected_1=$(yarn nx print-affected --base=$merge_base --head=$head_sha --select=projects || true)
# echo -n "Affected projects (allowed to fail): $affected_1"
# affected=$(yarn nx print-affected --base=${{ github.base_ref || github.ref_name }} --head=${{ github.head_ref }} --select=projects)
# echo -n "Affected projects: $affected"
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=HEAD --select=projects)"
affected=$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)
echo -n "Affected projects: $affected"
projects_e2e=""
if [[ $affected == *"governance"* ]]; then projects_e2e+='"governance-e2e" '; fi
if [[ $affected == *"trading"* ]]; then projects_e2e+='"trading-e2e" '; fi
-1
View File
@@ -8,7 +8,6 @@ on:
required: true
type: choice
options:
- announcements
- ui-toolkit
- react-helpers
- tailwindcss-config
-1
View File
@@ -3,7 +3,6 @@ NX_TENDERMINT_URL=http://localhost:26617
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
NX_VEGA_ENV=CUSTOM
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
# App flags
NX_EXPLORER_ASSETS=1
-1
View File
@@ -8,4 +8,3 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://dev.token.vega.xyz
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
-1
View File
@@ -6,4 +6,3 @@ NX_VEGA_ENV=MAINNET
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest/
NX_ETHERSCAN_URL=https://etherscan.io
NX_VEGA_GOVERNANCE_URL=https://token.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
-1
View File
@@ -6,7 +6,6 @@ NX_VEGA_ENV=MIRROR
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.xyz/rest/
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://mainnet-mirror.token.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
# App flags
NX_EXPLORER_ASSETS=1
-1
View File
@@ -9,4 +9,3 @@ NX_TENDERMINT_URL=https://tm.sandbox.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.sandbox.vega.xyz/websocket
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://sandbox.token.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
-1
View File
@@ -11,4 +11,3 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://stagnet1.token.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
-1
View File
@@ -5,4 +5,3 @@ NX_VEGA_ENV=STAGNET3
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
NX_VEGA_GOVERNANCE_URL=https://stagnet3.token.vega.xyz
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases/
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
-1
View File
@@ -8,4 +8,3 @@ NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://token.fairground.wtf
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
-1
View File
@@ -5,7 +5,6 @@ NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_GOVERNANCE_URL=https://validator-testnet.governance.vega.xyz
NX_TENDERMINT_URL=https://tm-be.validators-testnet.vega.rocks
-1
View File
@@ -4,4 +4,3 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket
NX_VEGA_ENV=CUSTOM
NX_BLOCK_EXPLORER=
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
+32 -9
View File
@@ -3,14 +3,16 @@ import {
useAssetDetailsDialogStore,
} from '@vegaprotocol/assets';
import { t } from '@vegaprotocol/i18n';
import { useEnvironment } from '@vegaprotocol/environment';
import { AnnouncementBanner } from '@vegaprotocol/announcements';
import {
AnnouncementBanner,
BackgroundVideo,
BreadcrumbsContainer,
ButtonLink,
ExternalLink,
Icon,
} from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
import { useState } from 'react';
import {
isRouteErrorResponse,
Link,
@@ -35,9 +37,35 @@ const DialogsContainer = () => {
);
};
const MainnetSimAd = () => {
const [shouldDisplayBanner, setShouldDisplayBanner] = useState<boolean>(true);
// Return an empty div so that the grid layout in _app.page.ts
// renders correctly
if (!shouldDisplayBanner) {
return <div />;
}
return (
<AnnouncementBanner>
<div className="grid grid-cols-[auto_1fr] gap-4 font-alpha calt uppercase text-center text-lg text-white">
<button
className="flex items-center"
onClick={() => setShouldDisplayBanner(false)}
>
<Icon name="cross" className="w-6 h-6" ariaLabel="dismiss" />
</button>
<div>
<span className="pr-4">Mainnet sim 3 is live!</span>
<ExternalLink href="https://fairground.wtf/">Learn more</ExternalLink>
</div>
</div>
</AnnouncementBanner>
);
};
export const Layout = () => {
const isHome = Boolean(useMatch(Routes.HOME));
const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
return (
<>
<div
@@ -51,12 +79,7 @@ export const Layout = () => {
)}
>
<div>
{ANNOUNCEMENTS_CONFIG_URL && (
<AnnouncementBanner
app="explorer"
configUrl={ANNOUNCEMENTS_CONFIG_URL}
/>
)}
<MainnetSimAd />
<Header />
</div>
<div>
@@ -25,24 +25,22 @@ import {
vegaWalletSetSpecifiedApprovalAmount,
vegaWalletTeardown,
} from '../../support/wallet-teardown.functions';
const stakeValidatorListTotalStake = 'total-stake';
const stakeValidatorListTotalShare = 'total-stake-share';
const stakeValidatorListStakePercentage = 'stake-percentage';
const userStakeBtn = 'my-stake-btn';
const userStake = 'user-stake';
const userStakeShare = 'user-stake-share';
const viewAllValidatorsToggle = 'validators-view-toggle-all';
const viewStakedByMeToggle = 'validators-view-toggle-myStake';
const stakeRemoveStakeRadioButton = 'remove-stake-radio';
const stakeTokenAmountInputBox = 'token-amount-input';
const stakeTokenSubmitButton = 'token-input-submit-button';
const stakeAddStakeRadioButton = 'add-stake-radio';
const stakeMaximumTokens = 'token-amount-use-maximum';
const vegaWalletAssociatedBalance = 'currency-value';
const vegaWalletStakedBalances = 'vega-wallet-balance-staked-validators';
const ethWalletContainer = 'ethereum-wallet';
const vegaWallet = 'vega-wallet';
const stakeValidatorListTotalStake = '[col-id="stake"] > div > span';
const stakeValidatorListTotalShare = '[col-id="stakeShare"] > div > span';
const stakeValidatorListValidatorStake = '[col-id="stake"] > div > span';
const stakeRemoveStakeRadioButton = '[data-testid="remove-stake-radio"]';
const stakeTokenAmountInputBox = '[data-testid="token-amount-input"]';
const stakeTokenSubmitButton = '[data-testid="token-input-submit-button"]';
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 vegaWalletStakedBalances =
'[data-testid="vega-wallet-balance-staked-validators"]';
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
const vegaWallet = '[data-testid="vega-wallet"]';
const txTimeout = Cypress.env('txTimeout');
const epochTimeout = Cypress.env('epochTimeout');
@@ -93,39 +91,6 @@ context(
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
});
it('Able to view validators staked by me', function () {
ensureSpecifiedUnstakedTokensAreAssociated('4');
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('2');
closeStakingDialog();
navigateTo(navigation.validators);
cy.getByTestId(userStake, epochTimeout)
.first()
.should('have.text', '2.00');
cy.getByTestId('total-stake').first().realHover();
cy.getByTestId('staked-by-user-tooltip')
.first()
.should('have.text', 'Staked by me: 2.00');
cy.getByTestId('total-pending-stake').first().realHover();
cy.getByTestId('pending-user-stake-tooltip')
.first()
.should('have.text', 'My pending stake: 0.00');
cy.getByTestId(userStakeShare).invoke('text').should('not.be.empty'); // Adjust when #3286 is resolved
cy.getByTestId(userStakeBtn).should('exist').click();
verifyThisEpochValue(2.0);
navigateTo(navigation.validators);
cy.getByTestId(viewStakedByMeToggle).click();
cy.getByTestId(userStakeBtn).should('have.length', 1);
cy.getByTestId(viewAllValidatorsToggle).click();
clickOnValidatorFromList(1);
stakingValidatorPageAddStake('2');
closeStakingDialog();
navigateTo(navigation.validators);
cy.getByTestId(viewStakedByMeToggle).click();
cy.getByTestId(userStakeBtn).should('have.length', 2);
});
it('Able to stake against a validator - using vega from vesting contract', function () {
stakingPageAssociateTokens('3', { type: 'contract' });
verifyUnstakedBalance(3.0);
@@ -144,13 +109,14 @@ context(
});
it('Able to stake against a validator - using vega from both wallet and vesting contract', function () {
vegaWalletTeardown();
stakingPageAssociateTokens('3', { type: 'contract' });
navigateTo(navigation.validators);
stakingPageAssociateTokens('4', { type: 'wallet' });
verifyUnstakedBalance(7.0);
verifyEthWalletTotalAssociatedBalance('3.0');
verifyEthWalletTotalAssociatedBalance('4.0');
verifyEthWalletTotalAssociatedBalance('3.0');
verifyEthWalletTotalAssociatedBalance('4.0');
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('6');
@@ -170,7 +136,7 @@ context(
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('2');
verifyUnstakedBalance(3.0);
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
cy.get(vegaWalletStakedBalances, txTimeout)
.parent()
.should('contain', 2.0, txTimeout);
closeStakingDialog();
@@ -178,36 +144,36 @@ context(
clickOnValidatorFromList(1);
stakingValidatorPageAddStake('1');
verifyUnstakedBalance(2.0);
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
cy.get(vegaWalletStakedBalances, txTimeout)
.should('have.length', 4, txTimeout)
.eq(0)
.should('contain', 2.0, txTimeout);
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
cy.get(vegaWalletStakedBalances, txTimeout)
.eq(1)
.should('contain', 1.0, txTimeout);
closeStakingDialog();
navigateTo(navigation.validators);
cy.get(`[row-id="${0}"]`).within(() => {
cy.getByTestId(stakeValidatorListTotalStake)
cy.get(stakeValidatorListTotalStake)
.should('have.text', '2.00')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalShare)
cy.get(stakeValidatorListTotalShare)
.should('have.text', '66.67%')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalStake)
cy.get(stakeValidatorListValidatorStake)
.scrollIntoView()
.should('have.text', '2.00')
.and('be.visible');
});
cy.get(`[row-id="${1}"]`).within(() => {
cy.getByTestId(stakeValidatorListTotalStake)
cy.get(stakeValidatorListTotalStake)
.scrollIntoView()
.should('have.text', '1.00')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalShare)
cy.get(stakeValidatorListTotalShare)
.should('have.text', '33.33%')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalStake)
cy.get(stakeValidatorListValidatorStake)
.scrollIntoView()
.should('have.text', '1.00')
.and('be.visible');
@@ -237,15 +203,9 @@ context(
verifyStakedBalance(2.0);
verifyNextEpochValue(2.0);
verifyThisEpochValue(2.0);
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
'contain.text',
'2'
);
cy.get(totalStake, epochTimeout).should('contain.text', '2');
waitForBeginningOfEpoch();
cy.getByTestId(stakeValidatorListStakePercentage).should(
'have.text',
'100%'
);
cy.get(stakeShare).should('have.text', '100%');
navigateTo(navigation.validators);
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
}
@@ -267,16 +227,12 @@ context(
verifyUnstakedBalance(3.0);
verifyNextEpochValue(0.0);
verifyThisEpochValue(0.0);
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
cy.get(vegaWalletStakedBalances, txTimeout).should(
'not.exist',
txTimeout
);
navigateTo(navigation.validators);
validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%');
cy.getByTestId(userStakeBtn).should('not.exist');
cy.getByTestId(userStake).should('not.exist');
cy.getByTestId(userStakeShare).should('not.exist');
});
it('Unable to remove a stake with a negative value for a validator', function () {
@@ -290,10 +246,10 @@ context(
closeStakingDialog();
navigateTo(navigation.validators);
clickOnValidatorFromList(0);
cy.getByTestId(stakeRemoveStakeRadioButton, txTimeout).click();
cy.getByTestId(stakeTokenAmountInputBox).type('-0.1');
cy.get(stakeRemoveStakeRadioButton, txTimeout).click();
cy.get(stakeTokenAmountInputBox).type('-0.1');
cy.contains('Waiting for next epoch to start', epochTimeout);
cy.getByTestId(stakeTokenSubmitButton)
cy.get(stakeTokenSubmitButton)
.should('be.disabled', epochTimeout)
.and('contain', `Remove -0.1 $VEGA tokens at the end of epoch`)
.and('be.visible');
@@ -310,10 +266,10 @@ context(
closeStakingDialog();
navigateTo(navigation.validators);
clickOnValidatorFromList(0);
cy.getByTestId(stakeRemoveStakeRadioButton).click();
cy.getByTestId(stakeTokenAmountInputBox).type('4');
cy.get(stakeRemoveStakeRadioButton).click();
cy.get(stakeTokenAmountInputBox).type('4');
cy.contains('Waiting for next epoch to start', epochTimeout);
cy.getByTestId(stakeTokenSubmitButton)
cy.get(stakeTokenSubmitButton)
.should('be.disabled', epochTimeout)
.and('contain', `Remove 4 $VEGA tokens at the end of epoch`)
.and('be.visible');
@@ -329,17 +285,17 @@ context(
verifyStakedBalance(2.0);
closeStakingDialog();
stakingPageDisassociateAllTokens();
cy.getByTestId(ethWalletContainer).within(() => {
cy.get(ethWalletContainer).within(() => {
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
});
verifyEthWalletTotalAssociatedBalance('0.0');
cy.getByTestId(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'0.00'
);
});
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
cy.get(vegaWalletStakedBalances, txTimeout).should(
'not.exist',
txTimeout
);
@@ -357,17 +313,17 @@ context(
verifyStakedBalance(2.0);
closeStakingDialog();
stakingPageDisassociateAllTokens('contract');
cy.getByTestId(ethWalletContainer).within(() => {
cy.get(ethWalletContainer).within(() => {
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
});
verifyEthWalletTotalAssociatedBalance('0.0');
cy.getByTestId(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'0.00'
);
});
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
cy.get(vegaWalletStakedBalances, txTimeout).should(
'not.exist',
txTimeout
);
@@ -386,8 +342,8 @@ context(
closeStakingDialog();
stakingPageDisassociateTokens('1');
verifyEthWalletTotalAssociatedBalance('2.0');
cy.getByTestId(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'2.00'
);
@@ -453,8 +409,8 @@ context(
verifyUnstakedBalance(0.0);
closeStakingDialog();
stakingPageAssociateTokens('6');
cy.getByTestId(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'12.00'
);
@@ -473,12 +429,9 @@ context(
verifyUnstakedBalance(1.0);
closeStakingDialog();
clickOnValidatorFromList(0);
cy.getByTestId(stakeAddStakeRadioButton).click();
cy.getByTestId(stakeMaximumTokens, { timeout: 60000 }).click();
cy.getByTestId(stakeTokenSubmitButton).should(
'contain',
'Add 1 $VEGA tokens'
);
cy.get(stakeAddStakeRadioButton).click();
cy.get(stakeMaximumTokens, { timeout: 60000 }).click();
cy.get(stakeTokenSubmitButton).should('contain', 'Add 1 $VEGA tokens');
});
afterEach('Teardown Wallet', function () {
@@ -26,19 +26,19 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
cy.connectPublicKey(vegaWalletPubKey);
});
it('Able to connect public key using url', function () {
cy.getByTestId('exit-view').click();
cy.visit(`/?address=${vegaWalletPubKey}`);
verifyConnectedToPubKey();
});
it('Able to connect public key via wallet and view assets in wallet', function () {
it('Able to connect public key via wallet', function () {
verifyConnectedToPubKey();
cy.getByTestId('currency-title', { timeout: 10000 })
.should('have.length.at.least', 4)
.and('contain.text', 'USDC (fake)');
});
it('Able to connect public key using url', function () {
cy.getByTestId('exit-view').click();
cy.visit(`/?address=${vegaWalletPubKey}`);
verifyConnectedToPubKey();
});
it('Unable to submit proposal with public key', function () {
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
@@ -74,7 +74,7 @@ context('Validators Page - verify elements on page', function () {
});
it('Should be able to see validator stake', function () {
cy.getByTestId('total-stake')
cy.get('[col-id="stake"] > div > span > span')
.should('have.length.at.least', 1)
.each(($stake) => {
cy.wrap($stake).should('not.be.empty');
@@ -82,7 +82,7 @@ context('Validators Page - verify elements on page', function () {
});
it('Should be able to see validator stake tooltip', function () {
cy.getByTestId('total-stake').first().realHover();
cy.get('[col-id="stake"] > div > span > span').first().realHover();
cy.get(stakedByOperatorToolTip)
.invoke('text')
@@ -96,15 +96,17 @@ context('Validators Page - verify elements on page', function () {
});
it('Should be able to see validator normalised voting power', function () {
cy.getByTestId('normalised-voting-power')
cy.get('[col-id="normalisedVotingPower"] > div > span > span')
.should('have.length.at.least', 1)
.each(($vPower) => {
cy.wrap($vPower).should('not.be.empty');
});
});
it('Should be able to see validator normalised voting power tooltip', function () {
cy.getByTestId('normalised-voting-power').first().realHover();
it('Should be able to see validator voting power tooltip', function () {
cy.get('[col-id="normalisedVotingPower"] > div > span > span')
.first()
.realHover();
cy.get(unnormalisedVotingPowerToolTip)
.invoke('text')
@@ -116,7 +118,7 @@ context('Validators Page - verify elements on page', function () {
// 2002-SINC-018
it('Should be able to see validator total penalties', function () {
cy.getByTestId('total-penalty')
cy.get('[col-id="totalPenalties"] > div > span > span')
.should('have.length.at.least', 1)
.each(($penalties) => {
cy.wrap($penalties).should('contain.text', '0%');
@@ -124,7 +126,7 @@ context('Validators Page - verify elements on page', function () {
});
it('Should be able to see validator penalties tooltip', function () {
cy.getByTestId('total-penalty').realHover();
cy.get('[col-id="totalPenalties"] > div > span > span').realHover();
cy.get(performancePenaltyToolTip)
.invoke('text')
@@ -138,7 +140,7 @@ context('Validators Page - verify elements on page', function () {
});
it('Should be able to see validator pending stake', function () {
cy.getByTestId('total-pending-stake')
cy.get('[col-id="pendingStake"] > div > span')
.should('have.length.at.least', 1)
.each(($pendingStake) => {
cy.wrap($pendingStake).should('contain.text', '0.00');
@@ -14,8 +14,8 @@ const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
const associateContractRadioButton = '[data-testid="associate-radio-contract"]';
const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]';
const stakeValidatorListPendingStake = '[col-id="pendingStake"]';
const stakeValidatorListTotalStake = 'total-stake';
const stakeValidatorListTotalShare = 'total-stake-share';
const stakeValidatorListTotalStake = '[col-id="stake"] > div > span';
const stakeValidatorListTotalShare = '[col-id="stakeShare"] > div > span';
const stakeValidatorListName = '[col-id="validator"]';
const vegaKeySelector = '#vega-key-selector';
const dialogCloseButton = '[data-testid="dialog-close"]';
@@ -185,11 +185,11 @@ export function validateValidatorListTotalStakeAndShare(
cy.contains('Loading...', epochTimeout).should('not.exist');
waitForBeginningOfEpoch();
cy.get(`[row-id="${positionOnList}"]`).within(() => {
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
cy.get(stakeValidatorListTotalStake, epochTimeout).should(
'have.text',
expectedTotalStake
);
cy.getByTestId(stakeValidatorListTotalShare, epochTimeout).should(
cy.get(stakeValidatorListTotalShare, epochTimeout).should(
'have.text',
expectedTotalShare
);
@@ -73,6 +73,9 @@ export async function vegaWalletTeardown() {
}
});
cy.get(vegaWalletContainer).within(() => {
cy.getByTestId('vega-wallet-balance-staked-validators', {
timeout: transactionTimeout,
}).should('not.exist');
cy.getByTestId('associated-amount', {
timeout: transactionTimeout,
}).contains('0.00', {
@@ -122,9 +125,6 @@ async function vegaWalletTeardownVesting(vestingContract: TokenVesting) {
log: false,
}).then((vestingAmount) => {
if (Number(vestingAmount) != 0) {
// Wait needed to allow time for ganache to process tx for stakingBridgeContract.remove_stake
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000);
cy.wrap(
vestingContract.remove_stake(String(vestingAmount), vegaWalletPubKey),
{ timeout: transactionTimeout, log: false }
-1
View File
@@ -13,7 +13,6 @@ NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
#Test configuration variables
CYPRESS_FAIRGROUND=false
-1
View File
@@ -16,7 +16,6 @@ NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
#Test configuration variables
CYPRESS_FAIRGROUND=false
-1
View File
@@ -10,4 +10,3 @@ NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
-1
View File
@@ -11,4 +11,3 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
-1
View File
@@ -9,4 +9,3 @@ NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_VEGA_EXPLORER_URL=https://mirror.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_DELEGATIONS_PAGINATION=50
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
-1
View File
@@ -6,4 +6,3 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-inter
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
-1
View File
@@ -7,4 +7,3 @@ NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
-1
View File
@@ -8,4 +8,3 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
-1
View File
@@ -11,4 +11,3 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
@@ -1,6 +1,9 @@
import { Networks, useEnvironment } from '@vegaprotocol/environment';
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
import { AnnouncementBanner } from '@vegaprotocol/announcements';
import {
ViewingAsBanner,
AnnouncementBanner,
ExternalLink,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import React from 'react';
@@ -12,16 +15,18 @@ export interface TemplateSidebarProps {
}
export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
const { VEGA_ENV, ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
const { VEGA_ENV } = useEnvironment();
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
return (
<>
{ANNOUNCEMENTS_CONFIG_URL && (
<AnnouncementBanner
app="governance"
configUrl={ANNOUNCEMENTS_CONFIG_URL}
/>
)}
<AnnouncementBanner>
<div className="font-alpha calt uppercase text-center text-lg text-white">
<span className="pr-4">Wait no longer, SIM3 is here!</span>
<ExternalLink href="https://fairground.wtf/sim3">
Learn more
</ExternalLink>
</div>
</AnnouncementBanner>
<Nav theme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'} />
{isReadOnly ? (
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
@@ -602,14 +602,11 @@
"noValidators": "No validators",
"validator": "Validator",
"stake": "Stake",
"myStake": "My stake",
"stakeShare": "Stake share",
"stakedByOperator": "Staked by operator",
"stakedByDelegates": "Staked by delegates",
"stakedByMe": "Staked by me",
"totalStake": "Total stake",
"pendingStake": "Pending stake",
"myPendingStake": "My pending stake",
"totalPenalties": "Total penalties",
"noPenaltyDataFromLastEpoch": "No penalty data from last epoch",
"stakeNeededForPromotion": "Stake needed for promotion",
+2 -2
View File
@@ -12,14 +12,14 @@ import { useRefreshAfterEpoch } from '../../hooks/use-refresh-after-epoch';
import { ProposalsListItem } from '../proposals/components/proposals-list-item';
import Routes from '../routes';
import { ExternalLinks, removePaginationWrapper } from '@vegaprotocol/utils';
import { useNodesQuery } from '../staking/home/__generated__/Nodes';
import { useNodesQuery } from '../staking/home/__generated___/Nodes';
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
import { getNotRejectedProposals } from '../proposals/proposals/proposals-container';
import { Heading } from '../../components/heading';
import * as Schema from '@vegaprotocol/types';
import type { RouteChildProps } from '..';
import type { ProposalFieldsFragment } from '../proposals/proposals/__generated__/Proposals';
import type { NodesFragmentFragment } from '../staking/home/__generated__/Nodes';
import type { NodesFragmentFragment } from '../staking/home/__generated___/Nodes';
const nodesToShow = 6;
@@ -16,8 +16,12 @@ import orderBy from 'lodash/orderBy';
const orderByDate = (arr: ProposalFieldsFragment[]) =>
orderBy(
arr,
[(p) => new Date(p?.terms?.closingDatetime).getTime(), (p) => p.id],
['desc', 'desc']
[
(p) => new Date(p?.terms?.enactmentDatetime || 0).getTime(), // has to be defaulted to 0 because new Date(null).getTime() -> NaN which is first when ordered.
(p) => new Date(p?.terms?.closingDatetime).getTime(),
(p) => p.id,
],
['desc', 'desc', 'desc']
);
export function getNotRejectedProposals<T extends ProposalFieldsFragment>(
@@ -21,12 +21,6 @@ export const EpochIndividualRewards = () => {
first: Number(delegationsPagination),
}
: undefined,
// we can use the same value for rewardsPagination as delegationsPagination
rewardsPagination: delegationsPagination
? {
first: Number(delegationsPagination),
}
: undefined,
},
skip: !pubKey,
});
@@ -21,14 +21,10 @@ fragment DelegationFields on Delegation {
epoch
}
query Rewards(
$partyId: ID!
$delegationsPagination: Pagination
$rewardsPagination: Pagination
) {
query Rewards($partyId: ID!, $delegationsPagination: Pagination) {
party(id: $partyId) {
id
rewardsConnection(pagination: $rewardsPagination) {
rewardsConnection {
edges {
node {
...RewardFields
@@ -10,7 +10,6 @@ export type DelegationFieldsFragment = { __typename?: 'Delegation', amount: stri
export type RewardsQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
delegationsPagination?: Types.InputMaybe<Types.Pagination>;
rewardsPagination?: Types.InputMaybe<Types.Pagination>;
}>;
@@ -76,10 +75,10 @@ export const EpochFieldsFragmentDoc = gql`
}
`;
export const RewardsDocument = gql`
query Rewards($partyId: ID!, $delegationsPagination: Pagination, $rewardsPagination: Pagination) {
query Rewards($partyId: ID!, $delegationsPagination: Pagination) {
party(id: $partyId) {
id
rewardsConnection(pagination: $rewardsPagination) {
rewardsConnection {
edges {
node {
...RewardFields
@@ -120,7 +119,6 @@ ${DelegationFieldsFragmentDoc}`;
* variables: {
* partyId: // value for 'partyId'
* delegationsPagination: // value for 'delegationsPagination'
* rewardsPagination: // value for 'rewardsPagination'
* },
* });
*/
@@ -104,7 +104,7 @@ export const RewardsPage = () => {
</section>
)}
<section className="grid xl:grid-cols-[1fr_auto] gap-12 items-center mb-8">
<section className="grid xl:grid-cols-2 gap-12 items-center mb-8">
<div>
<SubHeading title={t('rewardsAndFeesReceived')} />
<p>
@@ -114,7 +114,7 @@ export const RewardsPage = () => {
</p>
</div>
<div className="w-[440px]">
<div className="max-w-[600px]">
<Toggle
name="epoch-reward-view-toggle"
toggles={[
@@ -0,0 +1,106 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type PreviousEpochQueryVariables = Types.Exact<{
epochId?: Types.InputMaybe<Types.Scalars['ID']>;
}>;
export type PreviousEpochQuery = {
__typename?: 'Query';
epoch: {
__typename?: 'Epoch';
id: string;
validatorsConnection?: {
__typename?: 'NodesConnection';
edges?: Array<{
__typename?: 'NodeEdge';
node: {
__typename?: 'Node';
id: string;
rewardScore?: {
__typename?: 'RewardScore';
rawValidatorScore: string;
} | null;
rankingScore: {
__typename?: 'RankingScore';
performanceScore: string;
};
};
} | null> | null;
} | null;
};
};
export const PreviousEpochDocument = gql`
query PreviousEpoch($epochId: ID) {
epoch(id: $epochId) {
id
validatorsConnection {
edges {
node {
id
rewardScore {
rawValidatorScore
}
rankingScore {
performanceScore
}
}
}
}
}
}
`;
/**
* __usePreviousEpochQuery__
*
* To run a query within a React component, call `usePreviousEpochQuery` and pass it any options that fit your needs.
* When your component renders, `usePreviousEpochQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = usePreviousEpochQuery({
* variables: {
* epochId: // value for 'epochId'
* },
* });
*/
export function usePreviousEpochQuery(
baseOptions?: Apollo.QueryHookOptions<
PreviousEpochQuery,
PreviousEpochQueryVariables
>
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useQuery<PreviousEpochQuery, PreviousEpochQueryVariables>(
PreviousEpochDocument,
options
);
}
export function usePreviousEpochLazyQuery(
baseOptions?: Apollo.LazyQueryHookOptions<
PreviousEpochQuery,
PreviousEpochQueryVariables
>
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useLazyQuery<PreviousEpochQuery, PreviousEpochQueryVariables>(
PreviousEpochDocument,
options
);
}
export type PreviousEpochQueryHookResult = ReturnType<
typeof usePreviousEpochQuery
>;
export type PreviousEpochLazyQueryHookResult = ReturnType<
typeof usePreviousEpochLazyQuery
>;
export type PreviousEpochQueryResult = Apollo.QueryResult<
PreviousEpochQuery,
PreviousEpochQueryVariables
>;
@@ -0,0 +1,114 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type LinkingsFieldsFragment = {
__typename?: 'StakeLinking';
id: string;
txHash: string;
status: Types.StakeLinkingStatus;
};
export type PartyStakeLinkingsQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
}>;
export type PartyStakeLinkingsQuery = {
__typename?: 'Query';
party?: {
__typename?: 'Party';
id: string;
stakingSummary: {
__typename?: 'StakingSummary';
linkings: {
__typename?: 'StakesConnection';
edges?: Array<{
__typename?: 'StakeLinkingEdge';
node: {
__typename?: 'StakeLinking';
id: string;
txHash: string;
status: Types.StakeLinkingStatus;
};
} | null> | null;
};
};
} | null;
};
export const LinkingsFieldsFragmentDoc = gql`
fragment LinkingsFields on StakeLinking {
id
txHash
status
}
`;
export const PartyStakeLinkingsDocument = gql`
query PartyStakeLinkings($partyId: ID!) {
party(id: $partyId) {
id
stakingSummary {
linkings {
edges {
node {
...LinkingsFields
}
}
}
}
}
}
${LinkingsFieldsFragmentDoc}
`;
/**
* __usePartyStakeLinkingsQuery__
*
* To run a query within a React component, call `usePartyStakeLinkingsQuery` and pass it any options that fit your needs.
* When your component renders, `usePartyStakeLinkingsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = usePartyStakeLinkingsQuery({
* variables: {
* partyId: // value for 'partyId'
* },
* });
*/
export function usePartyStakeLinkingsQuery(
baseOptions: Apollo.QueryHookOptions<
PartyStakeLinkingsQuery,
PartyStakeLinkingsQueryVariables
>
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useQuery<
PartyStakeLinkingsQuery,
PartyStakeLinkingsQueryVariables
>(PartyStakeLinkingsDocument, options);
}
export function usePartyStakeLinkingsLazyQuery(
baseOptions?: Apollo.LazyQueryHookOptions<
PartyStakeLinkingsQuery,
PartyStakeLinkingsQueryVariables
>
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useLazyQuery<
PartyStakeLinkingsQuery,
PartyStakeLinkingsQueryVariables
>(PartyStakeLinkingsDocument, options);
}
export type PartyStakeLinkingsQueryHookResult = ReturnType<
typeof usePartyStakeLinkingsQuery
>;
export type PartyStakeLinkingsLazyQueryHookResult = ReturnType<
typeof usePartyStakeLinkingsLazyQuery
>;
export type PartyStakeLinkingsQueryResult = Apollo.QueryResult<
PartyStakeLinkingsQuery,
PartyStakeLinkingsQueryVariables
>;
@@ -15,7 +15,7 @@ import {
} from '../../../hooks/transaction-reducer';
import Routes from '../../routes';
import { truncateMiddle } from '../../../lib/truncate-middle';
import type { LinkingsFieldsFragment } from './__generated__/PartyStakeLinkings';
import type { LinkingsFieldsFragment } from './__generated___/PartyStakeLinkings';
export const AssociateTransaction = ({
amount,
@@ -15,8 +15,8 @@ import type {
LinkingsFieldsFragment,
PartyStakeLinkingsQuery,
PartyStakeLinkingsQueryVariables,
} from './__generated__/PartyStakeLinkings';
import { PartyStakeLinkingsDocument } from './__generated__/PartyStakeLinkings';
} from './__generated___/PartyStakeLinkings';
import { PartyStakeLinkingsDocument } from './__generated___/PartyStakeLinkings';
export const useAddStake = (
address: string,
@@ -0,0 +1,149 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type NodesFragmentFragment = {
__typename?: 'Node';
avatarUrl?: string | null;
id: string;
name: string;
pubkey: string;
stakedByOperator: string;
stakedByDelegates: string;
stakedTotal: string;
pendingStake: string;
rankingScore: {
__typename?: 'RankingScore';
rankingScore: string;
stakeScore: string;
performanceScore: string;
votingPower: string;
status: Types.ValidatorStatus;
};
};
export type NodesQueryVariables = Types.Exact<{ [key: string]: never }>;
export type NodesQuery = {
__typename?: 'Query';
epoch: {
__typename?: 'Epoch';
id: string;
timestamps: {
__typename?: 'EpochTimestamps';
start?: any | null;
end?: any | null;
expiry?: any | null;
};
};
nodesConnection: {
__typename?: 'NodesConnection';
edges?: Array<{
__typename?: 'NodeEdge';
node: {
__typename?: 'Node';
avatarUrl?: string | null;
id: string;
name: string;
pubkey: string;
stakedByOperator: string;
stakedByDelegates: string;
stakedTotal: string;
pendingStake: string;
rankingScore: {
__typename?: 'RankingScore';
rankingScore: string;
stakeScore: string;
performanceScore: string;
votingPower: string;
status: Types.ValidatorStatus;
};
};
} | null> | null;
};
nodeData?: { __typename?: 'NodeData'; stakedTotal: string } | null;
};
export const NodesFragmentFragmentDoc = gql`
fragment NodesFragment on Node {
avatarUrl
id
name
pubkey
stakedByOperator
stakedByDelegates
stakedTotal
pendingStake
rankingScore {
rankingScore
stakeScore
performanceScore
votingPower
status
}
}
`;
export const NodesDocument = gql`
query Nodes {
epoch {
id
timestamps {
start
end
expiry
}
}
nodesConnection {
edges {
node {
...NodesFragment
}
}
}
nodeData {
stakedTotal
}
}
${NodesFragmentFragmentDoc}
`;
/**
* __useNodesQuery__
*
* To run a query within a React component, call `useNodesQuery` and pass it any options that fit your needs.
* When your component renders, `useNodesQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useNodesQuery({
* variables: {
* },
* });
*/
export function useNodesQuery(
baseOptions?: Apollo.QueryHookOptions<NodesQuery, NodesQueryVariables>
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useQuery<NodesQuery, NodesQueryVariables>(
NodesDocument,
options
);
}
export function useNodesLazyQuery(
baseOptions?: Apollo.LazyQueryHookOptions<NodesQuery, NodesQueryVariables>
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useLazyQuery<NodesQuery, NodesQueryVariables>(
NodesDocument,
options
);
}
export type NodesQueryHookResult = ReturnType<typeof useNodesQuery>;
export type NodesLazyQueryHookResult = ReturnType<typeof useNodesLazyQuery>;
export type NodesQueryResult = Apollo.QueryResult<
NodesQuery,
NodesQueryVariables
>;
@@ -1,53 +1,36 @@
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { EpochCountdown } from '../../../components/epoch-countdown';
import { useNodesQuery } from './__generated__/Nodes';
import { useStakingQuery } from '../__generated__/Staking';
import { usePreviousEpochQuery } from '../__generated__/PreviousEpoch';
import { useNodesQuery } from './__generated___/Nodes';
import { usePreviousEpochQuery } from '../__generated___/PreviousEpoch';
import { ValidatorTables } from './validator-tables';
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
import { useVegaWallet } from '@vegaprotocol/wallet';
export const EpochData = () => {
// errorPolicy due to vegaprotocol/vega issue 5898
const { pubKey } = useVegaWallet();
const {
data: nodesData,
error: nodesError,
loading: nodesLoading,
refetch,
} = useNodesQuery();
const { data: userStakingData } = useStakingQuery({
variables: {
partyId: pubKey || '',
},
});
const { data, error, loading, refetch } = useNodesQuery();
const { data: previousEpochData } = usePreviousEpochQuery({
variables: {
epochId: (Number(nodesData?.epoch.id) - 1).toString(),
epochId: (Number(data?.epoch.id) - 1).toString(),
},
skip: !nodesData?.epoch.id,
skip: !data?.epoch.id,
});
useRefreshAfterEpoch(nodesData?.epoch.timestamps.expiry, refetch);
useRefreshAfterEpoch(data?.epoch.timestamps.expiry, refetch);
return (
<AsyncRenderer loading={nodesLoading} error={nodesError} data={nodesData}>
{nodesData?.epoch &&
nodesData.epoch.timestamps.start &&
nodesData?.epoch.timestamps.expiry && (
<AsyncRenderer loading={loading} error={error} data={data}>
{data?.epoch &&
data.epoch.timestamps.start &&
data?.epoch.timestamps.expiry && (
<div className="mb-10">
<EpochCountdown
id={nodesData.epoch.id}
startDate={new Date(nodesData.epoch.timestamps.start)}
endDate={new Date(nodesData.epoch.timestamps.expiry)}
id={data.epoch.id}
startDate={new Date(data.epoch.timestamps.start)}
endDate={new Date(data.epoch.timestamps.expiry)}
/>
</div>
)}
<ValidatorTables
nodesData={nodesData}
userStakingData={userStakingData}
previousEpochData={previousEpochData}
/>
<ValidatorTables data={data} previousEpochData={previousEpochData} />
</AsyncRenderer>
);
};
@@ -3,15 +3,14 @@ import { act, fireEvent, render, screen } from '@testing-library/react';
import { ConsensusValidatorsTable } from './consensus-validators-table';
import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter } from 'react-router-dom';
import { NodesDocument } from '../__generated__/Nodes';
import { PreviousEpochDocument } from '../../__generated__/PreviousEpoch';
import { NodesDocument } from '../__generated___/Nodes';
import { PreviousEpochDocument } from '../../__generated___/PreviousEpoch';
import * as Schema from '@vegaprotocol/types';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import type { MockedResponse } from '@apollo/client/testing';
import type { PartialDeep } from 'type-fest';
import type { NodesFragmentFragment } from '../__generated__/Nodes';
import type { PreviousEpochQuery } from '../../__generated__/PreviousEpoch';
import type { ValidatorsView } from './validator-tables';
import type { NodesFragmentFragment } from '../__generated___/Nodes';
import type { PreviousEpochQuery } from '../../__generated___/PreviousEpoch';
const nodeFactory = (
overrides?: PartialDeep<NodesFragmentFragment>
@@ -143,8 +142,7 @@ const MOCK_TOTAL_STAKE = '28832590188747439203824';
const renderValidatorsTable = (
data = MOCK_NODES,
previousEpochData = MOCK_PREVIOUS_EPOCH,
validatorsView: ValidatorsView = 'all'
previousEpochData = MOCK_PREVIOUS_EPOCH
) => {
return render(
<AppStateProvider initialState={{ decimals: 18 }}>
@@ -154,7 +152,6 @@ const renderValidatorsTable = (
data={data}
previousEpochData={previousEpochData}
totalStake={MOCK_TOTAL_STAKE}
validatorsView={validatorsView}
/>
</MockedProvider>
</MemoryRouter>
@@ -19,9 +19,7 @@ import {
import {
defaultColDef,
NODE_LIST_GRID_STYLES,
PendingStakeRenderer,
stakedTotalPercentage,
StakeShareRenderer,
TotalPenaltiesRenderer,
TotalStakeRenderer,
ValidatorFields,
@@ -56,9 +54,6 @@ interface CanonisedConsensusNodeProps {
[ValidatorFields.OVERSTAKING_PENALTY]: string;
[ValidatorFields.TOTAL_PENALTIES]: string;
[ValidatorFields.PENDING_STAKE]: string;
[ValidatorFields.STAKED_BY_USER]: string | undefined;
[ValidatorFields.PENDING_USER_STAKE]: string | undefined;
[ValidatorFields.USER_STAKE_SHARE]: string | undefined;
}
const getRowHeight = (params: RowHeightParams) => {
@@ -66,7 +61,7 @@ const getRowHeight = (params: RowHeightParams) => {
// Note: this value will change if the height of the top third cell renderer changes
return 138;
}
return 68;
return 52;
};
const TopThirdCellRenderer = (
@@ -122,7 +117,6 @@ export const ConsensusValidatorsTable = ({
data,
previousEpochData,
totalStake,
validatorsView,
}: ValidatorsTableProps) => {
const { t } = useTranslation();
const {
@@ -135,7 +129,7 @@ export const ConsensusValidatorsTable = ({
const nodes = useMemo(() => {
if (!data || !previousEpochData) return [];
let canonisedNodes = data
const canonisedNodes = data
.sort((a, b) => {
const aVotingPower = new BigNumber(a.rankingScore.votingPower);
const bVotingPower = new BigNumber(b.rankingScore.votingPower);
@@ -160,9 +154,6 @@ export const ConsensusValidatorsTable = ({
rankingScore: { stakeScore, votingPower },
pendingStake,
votingPowerRanking,
stakedByUser,
pendingUserStake,
userStakeShare,
}) => {
const { rawValidatorScore, performanceScore } =
getLastEpochScoreAndPerformance(previousEpochData, id);
@@ -210,28 +201,12 @@ export const ConsensusValidatorsTable = ({
totalStake
),
[ValidatorFields.PENDING_STAKE]: pendingStake,
[ValidatorFields.STAKED_BY_USER]: stakedByUser
? formatNumber(toBigNum(stakedByUser, decimals), 2)
: undefined,
[ValidatorFields.PENDING_USER_STAKE]: pendingUserStake,
[ValidatorFields.USER_STAKE_SHARE]: userStakeShare
? stakedTotalPercentage(userStakeShare)
: undefined,
decimals,
};
}
);
if (validatorsView === 'myStake') {
canonisedNodes = canonisedNodes.filter(
(node) => node[ValidatorFields.STAKED_BY_USER] !== undefined
);
}
if (
canonisedNodes.length < 3 ||
!hideTopThird ||
validatorsView === 'myStake'
) {
if (canonisedNodes.length < 3 || !hideTopThird) {
return canonisedNodes;
}
@@ -316,14 +291,7 @@ export const ConsensusValidatorsTable = ({
},
...remaining,
];
}, [
data,
decimals,
hideTopThird,
previousEpochData,
totalStake,
validatorsView,
]);
}, [data, decimals, hideTopThird, previousEpochData, totalStake]);
const ConsensusTable = forwardRef<AgGridReact>((_, gridRef) => {
const colDefs = useMemo<ColDef[]>(
@@ -343,7 +311,7 @@ export const ConsensusValidatorsTable = ({
return a > b ? 1 : -1;
},
pinned: 'left',
width: 260,
width: 240,
},
{
field: ValidatorFields.STAKE,
@@ -352,20 +320,6 @@ export const ConsensusValidatorsTable = ({
cellRenderer: TotalStakeRenderer,
width: 120,
},
{
field: ValidatorFields.PENDING_STAKE,
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
headerTooltip: t('PendingStakeDescription').toString(),
cellRenderer: PendingStakeRenderer,
width: 120,
},
{
field: ValidatorFields.STAKE_SHARE,
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
headerTooltip: t('StakeShareDescription').toString(),
cellRenderer: StakeShareRenderer,
width: 120,
},
{
field: ValidatorFields.NORMALISED_VOTING_POWER,
headerName: t(ValidatorFields.NORMALISED_VOTING_POWER).toString(),
@@ -374,6 +328,12 @@ export const ConsensusValidatorsTable = ({
width: 200,
sort: 'desc',
},
{
field: ValidatorFields.STAKE_SHARE,
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
headerTooltip: t('StakeShareDescription').toString(),
width: 100,
},
{
field: ValidatorFields.TOTAL_PENALTIES,
headerName: t(ValidatorFields.TOTAL_PENALTIES).toString(),
@@ -381,6 +341,14 @@ export const ConsensusValidatorsTable = ({
cellRenderer: TotalPenaltiesRenderer,
width: 120,
},
{
field: ValidatorFields.PENDING_STAKE,
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
headerTooltip: t('PendingStakeDescription').toString(),
valueFormatter: ({ value }) =>
formatNumber(toBigNum(value, decimals), 2),
width: 110,
},
],
[]
);
@@ -0,0 +1,70 @@
import {
getLastEpochScoreAndPerformance,
getTotalPenalties,
} from '../../shared';
import { stakedTotalPercentage } from './shared';
const MOCK_PREVIOUS_EPOCH = {
epoch: {
id: '1',
validatorsConnection: {
edges: [
{
node: {
id: '0x123',
rewardScore: {
rawValidatorScore: '0.25',
},
rankingScore: {
performanceScore: '0.75',
},
},
},
],
},
},
};
describe('stakedTotalPercentage', () => {
it('should return the correct percentage as a string, 2dp', () => {
expect(stakedTotalPercentage('1.2345')).toBe('123.45%');
});
});
describe('totalPenalties', () => {
it('should return the correct penalty based on arbitrary values, test 1', () => {
expect(
getTotalPenalties(
getLastEpochScoreAndPerformance(MOCK_PREVIOUS_EPOCH, '0x123')
.rawValidatorScore,
'0.1',
'5000',
'100000'
)
).toBe('50.00%');
});
it('should return the correct penalty based on lower performance score than first test', () => {
expect(
getTotalPenalties(
getLastEpochScoreAndPerformance(MOCK_PREVIOUS_EPOCH, '0x123')
.rawValidatorScore,
'0.05',
'5000',
'100000'
)
).toBe('75.00%');
});
it('should return the correct penalty based on higher amount of stake than other tests (great penalty due to anti-whaling)', () => {
expect(
getTotalPenalties(
getLastEpochScoreAndPerformance(MOCK_PREVIOUS_EPOCH, '0x123')
.rawValidatorScore,
'0.1',
'5000',
'5500'
)
).toBe('97.25%');
});
});
@@ -10,12 +10,9 @@ import {
Tooltip,
TooltipCellComponent,
} from '@vegaprotocol/ui-toolkit';
import { BigNumber } from '../../../../lib/bignumber';
import type { NodesFragmentFragment } from '../__generated__/Nodes';
import type { PreviousEpochQuery } from '../../__generated__/PreviousEpoch';
import type { NodesFragmentFragment } from '../__generated___/Nodes';
import type { PreviousEpochQuery } from '../../__generated___/PreviousEpoch';
import { useAppState } from '../../../../contexts/app-state/app-state-context';
import type { StakingDelegationFieldsFragment } from '../../__generated__/Staking';
import type { ValidatorsView } from './validator-tables';
export enum ValidatorFields {
RANKING_INDEX = 'rankingIndex',
@@ -34,49 +31,12 @@ export enum ValidatorFields {
PERFORMANCE_PENALTY = 'performancePenalty',
OVERSTAKED_AMOUNT = 'overstakedAmount',
OVERSTAKING_PENALTY = 'overstakingPenalty',
// the following are additional fields added to the validator object displaying user data
STAKED_BY_USER = 'stakedByUser',
PENDING_USER_STAKE = 'pendingUserStake',
USER_STAKE_SHARE = 'userStakeShare',
}
export const addUserDataToValidator = (
validator: NodesFragmentFragment,
currentEpochUserStaking: StakingDelegationFieldsFragment | undefined,
nextEpochUserStaking: StakingDelegationFieldsFragment | undefined,
currentUserStakeAvailable: string
) => {
return {
...validator,
[ValidatorFields.STAKED_BY_USER]:
currentEpochUserStaking && Number(currentEpochUserStaking?.amount) > 0
? currentEpochUserStaking.amount
: undefined,
[ValidatorFields.PENDING_USER_STAKE]: nextEpochUserStaking
? new BigNumber(nextEpochUserStaking?.amount)
.minus(new BigNumber(currentEpochUserStaking?.amount || 0))
.toString()
: undefined,
[ValidatorFields.USER_STAKE_SHARE]:
currentEpochUserStaking && Number(currentEpochUserStaking.amount) > 0
? new BigNumber(currentEpochUserStaking.amount).dividedBy(
new BigNumber(currentUserStakeAvailable)
)
: undefined,
};
};
export type ValidatorWithUserData = NodesFragmentFragment & {
stakedByUser?: string;
pendingUserStake?: string;
userStakeShare?: string;
};
export interface ValidatorsTableProps {
data: ValidatorWithUserData[] | undefined;
data: NodesFragmentFragment[] | undefined;
previousEpochData: PreviousEpochQuery | undefined;
totalStake: string;
validatorsView: ValidatorsView;
}
// Custom styling to account for the scrollbar. This is needed because the
@@ -98,23 +58,19 @@ export const defaultColDef = {
resizable: true,
autoHeight: true,
comparator: (a: string, b: string) => parseFloat(a) - parseFloat(b),
cellStyle: { margin: '10px 0', padding: '0 12px' },
tooltipComponent: TooltipCellComponent,
cellStyle: { display: 'flex', alignItems: 'center', padding: '0 10px' },
};
interface ValidatorRendererProps {
data: {
id: string;
validator: { avatarUrl: string; name: string };
stakedByUser: string | undefined;
};
data: { id: string; validator: { avatarUrl: string; name: string } };
}
export const ValidatorRenderer = ({ data }: ValidatorRendererProps) => {
const { t } = useTranslation();
const { avatarUrl, name } = data.validator;
return (
<div className="w-[238px] grid grid-cols-[1fr_auto] gap-2 items-center">
<div className="grid grid-cols-[1fr_auto] gap-2 items-center">
<span className="flex overflow-hidden">
{avatarUrl && (
<img
@@ -127,19 +83,9 @@ export const ValidatorRenderer = ({ data }: ValidatorRendererProps) => {
<span>{name}</span>
</span>
<Link to={data.id}>
{data.stakedByUser ? (
<Button
data-testid="my-stake-btn"
size="sm"
className="text-vega-green border-vega-green"
>
{t('myStake')}
</Button>
) : (
<Button data-testid="stake-btn" size="sm" fill={true}>
{t('Stake')}
</Button>
)}
<Button size="sm" fill={true}>
{t('Stake')}
</Button>
</Link>
</div>
);
@@ -156,14 +102,8 @@ export const StakeNeededForPromotionRenderer = ({
data,
}: StakeNeededForPromotionRendererProps) => {
return (
<Tooltip
description={
<span data-testid="stake-needed-for-promotion-tooltip">
{data.stakeNeededForPromotionDescription}
</span>
}
>
<span data-testid="stake-needed-for-promotion">
<Tooltip description={data.stakeNeededForPromotionDescription}>
<span>
{data.stakeNeededForPromotion &&
formatNumber(data.stakeNeededForPromotion, 2)}
</span>
@@ -194,59 +134,7 @@ export const VotingPowerRenderer = ({ data }: VotingPowerRendererProps) => {
</>
}
>
<span data-testid="normalised-voting-power">
{data.normalisedVotingPower}
</span>
</Tooltip>
);
};
interface PendingStakeRendererProps {
data: {
pendingStake: string;
pendingUserStake: string | undefined;
};
}
export const PendingStakeRenderer = ({ data }: PendingStakeRendererProps) => {
const { t } = useTranslation();
const {
appState: { decimals },
} = useAppState();
return (
<Tooltip
description={
<>
<div data-testid="pending-stake-tooltip">
{t('pendingStake')}:{' '}
{formatNumber(toBigNum(data.pendingStake, decimals), decimals)}
</div>
{data.pendingUserStake && (
<div
className="text-vega-green border-t border-t-vega-dark-200 mt-1.5 pt-1"
data-testid="pending-user-stake-tooltip"
>
{t('myPendingStake')}:{' '}
{formatNumber(
toBigNum(data.pendingUserStake, decimals),
decimals
)}
</div>
)}
</>
}
>
<div className="flex flex-col">
{data.pendingUserStake && data.pendingStake !== '0' && (
<span data-testid="pending-user-stake" className="text-vega-green">
{formatNumber(toBigNum(data.pendingUserStake, decimals), 2)}
</span>
)}
<span data-testid="total-pending-stake">
{formatNumber(toBigNum(data.pendingStake, decimals), 2)}
</span>
</div>
<span>{data.normalisedVotingPower}</span>
</Tooltip>
);
};
@@ -256,7 +144,6 @@ interface TotalStakeRendererProps {
stake: string;
stakedByDelegates: string;
stakedByOperator: string;
stakedByUser: string | undefined;
};
}
@@ -278,52 +165,18 @@ export const TotalStakeRenderer = ({ data }: TotalStakeRendererProps) => {
<div data-testid="staked-delegates-tooltip">
{t('stakedByDelegates')}: {data.stakedByDelegates.toString()}
</div>
<div className="font-bold" data-testid="total-staked-tooltip">
{t('totalStake')}: {formattedStake}
<div data-testid="total-staked-tooltip">
{t('totalStake')}:{' '}
<span className="font-bold">{formattedStake}</span>
</div>
{data.stakedByUser && (
<div
className="text-vega-green border-t border-t-vega-dark-200 mt-1.5 pt-1"
data-testid="staked-by-user-tooltip"
>
{t('stakedByMe')}: {data.stakedByUser}
</div>
)}
</>
}
>
<div className="flex flex-col">
{data.stakedByUser && (
<span data-testid="user-stake" className="text-vega-green">
{data.stakedByUser}
</span>
)}
<span data-testid="total-stake">{formattedStake}</span>
</div>
<span>{formattedStake}</span>
</Tooltip>
);
};
interface StakeShareRendererProps {
data: {
stakeShare: string;
userStakeShare: string | undefined;
};
}
export const StakeShareRenderer = ({ data }: StakeShareRendererProps) => {
return (
<div className="flex flex-col">
{data.userStakeShare && (
<span data-testid="user-stake-share" className="text-vega-green">
{data.userStakeShare}
</span>
)}
<span data-testid="total-stake-share">{data.stakeShare}</span>
</div>
);
};
interface TotalPenaltiesRendererProps {
data: {
performanceScore: string;
@@ -356,7 +209,7 @@ export const TotalPenaltiesRenderer = ({
</>
}
>
<span data-testid="total-penalty">{data.totalPenalties}</span>
<span>{data.totalPenalties}</span>
</Tooltip>
);
};
@@ -21,8 +21,6 @@ import {
ValidatorRenderer,
TotalPenaltiesRenderer,
TotalStakeRenderer,
StakeShareRenderer,
PendingStakeRenderer,
} from './shared';
import type { AgGridReact } from 'ag-grid-react';
import type { ColDef } from 'ag-grid-community';
@@ -40,7 +38,6 @@ export const StandbyPendingValidatorsTable = ({
totalStake,
stakeNeededForPromotion,
stakeNeededForPromotionDescription,
validatorsView,
}: StandbyPendingValidatorsTableProps) => {
const { t } = useTranslation();
const {
@@ -50,7 +47,7 @@ export const StandbyPendingValidatorsTable = ({
const gridRef = useRef<AgGridReact | null>(null);
let nodes = useMemo(() => {
const nodes = useMemo(() => {
if (!data) return [];
return data
@@ -78,9 +75,6 @@ export const StandbyPendingValidatorsTable = ({
rankingScore: { stakeScore },
pendingStake,
votingPowerRanking,
stakedByUser,
pendingUserStake,
userStakeShare,
}) => {
const { rawValidatorScore, performanceScore } =
getLastEpochScoreAndPerformance(previousEpochData, id);
@@ -158,13 +152,6 @@ export const StandbyPendingValidatorsTable = ({
totalStake
),
[ValidatorFields.PENDING_STAKE]: pendingStake,
[ValidatorFields.STAKED_BY_USER]: stakedByUser
? formatNumber(toBigNum(stakedByUser, decimals), 2)
: undefined,
[ValidatorFields.PENDING_USER_STAKE]: pendingUserStake,
[ValidatorFields.USER_STAKE_SHARE]: userStakeShare
? stakedTotalPercentage(userStakeShare)
: undefined,
};
}
);
@@ -178,12 +165,6 @@ export const StandbyPendingValidatorsTable = ({
totalStake,
]);
if (validatorsView === 'myStake') {
nodes = nodes.filter(
(node) => node[ValidatorFields.STAKED_BY_USER] !== undefined
);
}
const StandbyPendingTable = forwardRef<AgGridReact>((_, gridRef) => {
const colDefs = useMemo<ColDef[]>(
() => [
@@ -199,7 +180,7 @@ export const StandbyPendingValidatorsTable = ({
cellRenderer: ValidatorRenderer,
comparator: ({ name: a }, { name: b }) => Math.sign(a - b),
pinned: 'left',
width: 260,
width: 240,
},
{
field: ValidatorFields.STAKE,
@@ -208,20 +189,6 @@ export const StandbyPendingValidatorsTable = ({
cellRenderer: TotalStakeRenderer,
width: 120,
},
{
field: ValidatorFields.PENDING_STAKE,
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
headerTooltip: t('PendingStakeDescription').toString(),
cellRenderer: PendingStakeRenderer,
width: 120,
},
{
field: ValidatorFields.STAKE_SHARE,
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
headerTooltip: t('StakeShareDescription').toString(),
cellRenderer: StakeShareRenderer,
width: 100,
},
{
field: ValidatorFields.STAKE_NEEDED_FOR_PROMOTION,
headerName: t(ValidatorFields.STAKE_NEEDED_FOR_PROMOTION).toString(),
@@ -232,6 +199,12 @@ export const StandbyPendingValidatorsTable = ({
width: 210,
sort: 'asc',
},
{
field: ValidatorFields.STAKE_SHARE,
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
headerTooltip: t('StakeShareDescription').toString(),
width: 100,
},
{
field: ValidatorFields.TOTAL_PENALTIES,
headerName: t(ValidatorFields.TOTAL_PENALTIES).toString(),
@@ -239,6 +212,14 @@ export const StandbyPendingValidatorsTable = ({
cellRenderer: TotalPenaltiesRenderer,
width: 120,
},
{
field: ValidatorFields.PENDING_STAKE,
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
headerTooltip: t('PendingStakeDescription').toString(),
valueFormatter: ({ value }) =>
formatNumber(toBigNum(value, decimals), 2),
width: 110,
},
],
[]
);
@@ -249,7 +230,7 @@ export const StandbyPendingValidatorsTable = ({
domLayout="autoHeight"
style={{ width: '100%' }}
customThemeParams={NODE_LIST_GRID_STYLES}
rowHeight={68}
rowHeight={52}
defaultColDef={defaultColDef}
tooltipShowDelay={0}
animateRows={true}
@@ -1,30 +1,27 @@
import { useMemo, useState } from 'react';
import { useMemo } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import BigNumber from 'bignumber.js';
import { ConsensusValidatorsTable } from './consensus-validators-table';
import { StandbyPendingValidatorsTable } from './standby-pending-validators-table';
import * as Schema from '@vegaprotocol/types';
import { formatNumber } from '../../../../lib/format-number';
import {
createDocsLinks,
removePaginationWrapper,
toBigNum,
} from '@vegaprotocol/utils';
import { useEnvironment } from '@vegaprotocol/environment';
import { Link as UTLink, Toggle } from '@vegaprotocol/ui-toolkit';
import { formatNumber } from '../../../../lib/format-number';
import { Link as UTLink } from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
import { useEnvironment } from '@vegaprotocol/environment';
import { useAppState } from '../../../../contexts/app-state/app-state-context';
import { addUserDataToValidator } from './shared';
import { ConsensusValidatorsTable } from './consensus-validators-table';
import { StandbyPendingValidatorsTable } from './standby-pending-validators-table';
import type { NodesQuery, NodesFragmentFragment } from '../__generated__/Nodes';
import type { PreviousEpochQuery } from '../../__generated__/PreviousEpoch';
import type { StakingQuery } from '../../__generated__/Staking';
import type { StakingDelegationFieldsFragment } from '../../__generated__/Staking';
import type { ValidatorWithUserData } from './shared';
import type {
NodesQuery,
NodesFragmentFragment,
} from '../__generated___/Nodes';
import type { PreviousEpochQuery } from '../../__generated___/PreviousEpoch';
import BigNumber from 'bignumber.js';
export interface ValidatorsTableProps {
nodesData: NodesQuery | undefined;
userStakingData: StakingQuery | undefined;
data: NodesQuery | undefined;
previousEpochData: PreviousEpochQuery | undefined;
}
@@ -34,11 +31,8 @@ interface SortedValidatorsProps {
pendingValidators: NodesFragmentFragment[];
}
export type ValidatorsView = 'all' | 'myStake';
export const ValidatorTables = ({
nodesData,
userStakingData,
data,
previousEpochData,
}: ValidatorsTableProps) => {
const { t } = useTranslation();
@@ -46,69 +40,25 @@ export const ValidatorTables = ({
const {
appState: { decimals },
} = useAppState();
const [validatorsView, setValidatorsView] = useState<ValidatorsView>('all');
const totalStake = useMemo(
() => nodesData?.nodeData?.stakedTotal || '0',
[nodesData?.nodeData?.stakedTotal]
() => data?.nodeData?.stakedTotal || '0',
[data?.nodeData?.stakedTotal]
);
const epochId = useMemo(() => nodesData?.epoch.id, [nodesData?.epoch.id]);
const currentUserStakeAvailable = useMemo(
() => userStakingData?.party?.stakingSummary.currentStakeAvailable || '0',
[userStakingData?.party?.stakingSummary.currentStakeAvailable]
);
let stakeNeededForPromotion = undefined;
let delegations: StakingDelegationFieldsFragment[] | undefined = undefined;
if (userStakingData) {
delegations = removePaginationWrapper(
userStakingData?.party?.delegationsConnection?.edges
);
}
const { consensusValidators, standbyValidators, pendingValidators } = useMemo(
() =>
removePaginationWrapper(nodesData?.nodesConnection.edges).reduce(
removePaginationWrapper(data?.nodesConnection.edges).reduce(
(acc: SortedValidatorsProps, validator) => {
const validatorId = validator.id;
const currentDelegation = delegations?.find(
(d) => d.node.id === validatorId && d.epoch === Number(epochId)
);
const nextDelegation = delegations?.find(
(d) => d.node.id === validatorId && d.epoch === Number(epochId) + 1
);
switch (validator.rankingScore?.status) {
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT:
acc.consensusValidators.push(
addUserDataToValidator(
validator,
currentDelegation,
nextDelegation,
currentUserStakeAvailable
)
);
acc.consensusValidators.push(validator);
break;
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_ERSATZ:
acc.standbyValidators.push(
addUserDataToValidator(
validator,
currentDelegation,
nextDelegation,
currentUserStakeAvailable
)
);
acc.standbyValidators.push(validator);
break;
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_PENDING:
acc.pendingValidators.push(
addUserDataToValidator(
validator,
currentDelegation,
nextDelegation,
currentUserStakeAvailable
)
);
acc.pendingValidators.push(validator);
}
return acc;
},
@@ -118,12 +68,7 @@ export const ValidatorTables = ({
pendingValidators: [],
}
),
[
currentUserStakeAvailable,
delegations,
epochId,
nodesData?.nodesConnection.edges,
]
[data?.nodesConnection.edges]
);
if (
@@ -131,7 +76,7 @@ export const ValidatorTables = ({
(standbyValidators.length || pendingValidators.length)
) {
const lowestRankingConsensusScore = consensusValidators.reduce(
(lowest: ValidatorWithUserData, validator: ValidatorWithUserData) => {
(lowest: NodesFragmentFragment, validator: NodesFragmentFragment) => {
if (
Number(validator.rankingScore.rankingScore) <
Number(lowest.rankingScore.rankingScore)
@@ -153,42 +98,19 @@ export const ValidatorTables = ({
).toString();
}
return (
<section data-testid="validator-tables">
<div className="grid w-full justify-end">
<div className="w-[400px]">
<Toggle
name="validators-view-toggle"
toggles={[
{
label: t('ALL VALIDATORS'),
value: 'all',
},
{
label: t('STAKED BY ME'),
value: 'myStake',
},
]}
checkedValue={validatorsView}
onChange={(e) =>
setValidatorsView(e.target.value as ValidatorsView)
}
/>
</div>
</div>
<div data-testid="validator-tables">
{consensusValidators.length > 0 && (
<div className="mb-10">
<>
<SubHeading title={t('status-tendermint')} />
<ConsensusValidatorsTable
data={consensusValidators}
previousEpochData={previousEpochData}
totalStake={totalStake}
validatorsView={validatorsView}
/>
</div>
</>
)}
{standbyValidators.length > 0 && (
<div className="mb-10">
<>
<SubHeading title={t('status-ersatz')} />
<p>
<Trans
@@ -204,9 +126,8 @@ export const ValidatorTables = ({
totalStake={totalStake}
stakeNeededForPromotion={stakeNeededForPromotion}
stakeNeededForPromotionDescription="StakeNeededForPromotionStandbyDescription"
validatorsView={validatorsView}
/>
</div>
</>
)}
{pendingValidators.length > 0 && (
<>
@@ -234,10 +155,9 @@ export const ValidatorTables = ({
totalStake={totalStake}
stakeNeededForPromotion={stakeNeededForPromotion}
stakeNeededForPromotionDescription="StakeNeededForPromotionCandidateDescription"
validatorsView={validatorsView}
/>
</>
)}
</section>
</div>
);
};
@@ -23,17 +23,6 @@ fragment StakingNodeFields on Node {
}
}
fragment StakingDelegationFields on Delegation {
amount
epoch
node {
id
}
party {
id
}
}
query Staking($partyId: ID!, $delegationsPagination: Pagination) {
party(id: $partyId) {
id
@@ -43,7 +32,11 @@ query Staking($partyId: ID!, $delegationsPagination: Pagination) {
delegationsConnection(pagination: $delegationsPagination) {
edges {
node {
...StakingDelegationFields
amount
epoch
node {
id
}
}
}
}
@@ -5,15 +5,13 @@ import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type StakingNodeFieldsFragment = { __typename?: 'Node', id: string, name: string, pubkey: string, infoUrl: string, location: string, ethereumAddress: string, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null, rankingScore: { __typename?: 'RankingScore', rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string, status: Types.ValidatorStatus } };
export type StakingDelegationFieldsFragment = { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string }, party: { __typename?: 'Party', id: string } };
export type StakingQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
delegationsPagination?: Types.InputMaybe<Types.Pagination>;
}>;
export type StakingQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string }, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string }, party: { __typename?: 'Party', id: string } } } | null> | null } | null } | null, epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } }, nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, pubkey: string, infoUrl: string, location: string, ethereumAddress: string, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null, rankingScore: { __typename?: 'RankingScore', rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string, status: Types.ValidatorStatus } } } | null> | null }, nodeData?: { __typename?: 'NodeData', stakedTotal: string, totalNodes: number, inactiveNodes: number, uptime: number } | null };
export type StakingQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string }, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string } } } | null> | null } | null } | null, epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } }, nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, pubkey: string, infoUrl: string, location: string, ethereumAddress: string, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null, rankingScore: { __typename?: 'RankingScore', rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string, status: Types.ValidatorStatus } } } | null> | null }, nodeData?: { __typename?: 'NodeData', stakedTotal: string, totalNodes: number, inactiveNodes: number, uptime: number } | null };
export const StakingNodeFieldsFragmentDoc = gql`
fragment StakingNodeFields on Node {
@@ -41,18 +39,6 @@ export const StakingNodeFieldsFragmentDoc = gql`
}
}
`;
export const StakingDelegationFieldsFragmentDoc = gql`
fragment StakingDelegationFields on Delegation {
amount
epoch
node {
id
}
party {
id
}
}
`;
export const StakingDocument = gql`
query Staking($partyId: ID!, $delegationsPagination: Pagination) {
party(id: $partyId) {
@@ -63,7 +49,11 @@ export const StakingDocument = gql`
delegationsConnection(pagination: $delegationsPagination) {
edges {
node {
...StakingDelegationFields
amount
epoch
node {
id
}
}
}
}
@@ -90,8 +80,7 @@ export const StakingDocument = gql`
uptime
}
}
${StakingDelegationFieldsFragmentDoc}
${StakingNodeFieldsFragmentDoc}`;
${StakingNodeFieldsFragmentDoc}`;
/**
* __useStakingQuery__
@@ -20,8 +20,8 @@ import NodeContainer from './nodes-container';
import { useAppState } from '../../../contexts/app-state/app-state-context';
import { Heading, SubHeading } from '../../../components/heading';
import Routes from '../../routes';
import type { StakingQuery } from '../__generated__/Staking';
import type { PreviousEpochQuery } from '../__generated__/PreviousEpoch';
import type { StakingQuery } from './__generated__/Staking';
import type { PreviousEpochQuery } from '../__generated___/PreviousEpoch';
interface StakingNodeProps {
data?: StakingQuery;
@@ -116,6 +116,13 @@ export const StakingNode = ({ data, previousEpochData }: StakingNodeProps) => {
t('validatorTitle', { nodeName: t('validatorTitleFallback') })
}
/>
<section className="mb-4">
<ValidatorTable
node={nodeInfo}
stakedTotal={addDecimal(data?.nodeData?.stakedTotal || '0', decimals)}
previousEpochData={previousEpochData}
/>
</section>
{data?.epoch.timestamps.start && data?.epoch.timestamps.expiry && (
<section className="mb-10">
<EpochCountdown
@@ -150,13 +157,6 @@ export const StakingNode = ({ data, previousEpochData }: StakingNodeProps) => {
<ConnectToVega />
</>
)}
<section className="mb-4">
<ValidatorTable
node={nodeInfo}
stakedTotal={addDecimal(data?.nodeData?.stakedTotal || '0', decimals)}
previousEpochData={previousEpochData}
/>
</section>
</div>
);
};
@@ -4,11 +4,11 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
import { useTranslation } from 'react-i18next';
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
import { SplashLoader } from '../../../components/splash-loader';
import { useStakingQuery } from '../__generated__/Staking';
import { usePreviousEpochQuery } from '../__generated__/PreviousEpoch';
import { useStakingQuery } from './__generated__/Staking';
import { usePreviousEpochQuery } from '../__generated___/PreviousEpoch';
import type { ReactElement } from 'react';
import type { StakingQuery } from '../__generated__/Staking';
import type { PreviousEpochQuery } from '../__generated__/PreviousEpoch';
import type { StakingQuery } from './__generated__/Staking';
import type { PreviousEpochQuery } from '../__generated___/PreviousEpoch';
// TODO should only request a single node. When migrating from deprecated APIs we should address this.
@@ -28,8 +28,8 @@ import {
getStakePercentage,
} from '../shared';
import type { ReactNode } from 'react';
import type { StakingNodeFieldsFragment } from '../__generated__/Staking';
import type { PreviousEpochQuery } from '../__generated__/PreviousEpoch';
import type { StakingNodeFieldsFragment } from './__generated__/Staking';
import type { PreviousEpochQuery } from '../__generated___/PreviousEpoch';
const statuses = {
[Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_ERSATZ]: 'status-ersatz',
@@ -111,7 +111,7 @@ export const ValidatorTable = ({
<div className="my-12" data-testid="validator-table">
<SubHeading title={t('profile')} />
<RoundedWrapper paddingBottom={true}>
<RoundedWrapper>
<KeyValueTable data-testid="validator-table-profile">
<KeyValueTableRow>
<span>{t('id')}</span>
@@ -156,7 +156,7 @@ export const ValidatorTable = ({
</div>
<SubHeading title={t('ADDRESS')} />
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
<RoundedWrapper marginBottomLarge={true}>
<KeyValueTable data-testid="validator-table-address">
<KeyValueTableRow>
<span>{t('VEGA ADDRESS / PUBLIC KEY')}</span>
@@ -187,7 +187,7 @@ export const ValidatorTable = ({
</RoundedWrapper>
<SubHeading title={t('STAKE')} />
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
<RoundedWrapper marginBottomLarge={true}>
<KeyValueTable data-testid="validator-table-stake">
<KeyValueTableRow>
<span>{t('STAKED BY OPERATOR')}</span>
@@ -238,7 +238,7 @@ export const ValidatorTable = ({
</RoundedWrapper>
<SubHeading title={t('PENALTIES')} />
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
<RoundedWrapper marginBottomLarge={true}>
<KeyValueTable data-testid="validator-table-penalties">
<KeyValueTableRow>
<span>{t('OVERSTAKED PENALTY')}</span>
@@ -270,7 +270,7 @@ export const ValidatorTable = ({
</RoundedWrapper>
<SubHeading title={t('VOTING POWER')} />
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
<RoundedWrapper marginBottomLarge={true}>
<KeyValueTable data-testid="validator-table-voting-power">
<KeyValueTableRow>
<span>{t('UNNORMALISED VOTING POWER')}</span>
@@ -23,7 +23,7 @@ export const YourStake = ({
return (
<div data-testid="your-stake">
<SubHeading title={t('Your stake')} />
<RoundedWrapper paddingBottom={true}>
<RoundedWrapper>
<KeyValueTable>
<KeyValueTableRow>
{t('Your Stake On Node (This Epoch)')}
+1 -1
View File
@@ -2,7 +2,7 @@ import {
formatNumberPercentage,
removePaginationWrapper,
} from '@vegaprotocol/utils';
import type { PreviousEpochQuery } from './__generated__/PreviousEpoch';
import type { PreviousEpochQuery } from './__generated___/PreviousEpoch';
import { BigNumber } from '../../lib/bignumber';
export const getLastEpochScoreAndPerformance = (
+33 -108
View File
@@ -1,28 +1,12 @@
[
{
"tranche_id": 56,
"tranche_start": "2023-04-20T00:00:00.000Z",
"tranche_end": "2023-05-20T00:00:00.000Z",
"total_added": "0",
"total_removed": "0",
"locked_amount": "0",
"deposits": [],
"withdrawals": [],
"users": []
},
{
"tranche_id": 55,
"tranche_start": "2023-09-01T00:00:00.000Z",
"tranche_end": "2024-03-01T00:00:00.000Z",
"total_added": "17500",
"total_added": "5000",
"total_removed": "0",
"locked_amount": "17500",
"locked_amount": "5000",
"deposits": [
{
"amount": "12500",
"user": "0x52dD21Bd0A8fBD31f4D5002c34b98d0c328791c8",
"tx": "0x3d02aec9b4c1ff084ae4518b6a6f4647487c2724afc02c33f7dcd378d606f93f"
},
{
"amount": "5000",
"user": "0xbCDBCC3Ff54D659f2CC737bEf49B10D92dF3FDbf",
@@ -31,21 +15,6 @@
],
"withdrawals": [],
"users": [
{
"address": "0x52dD21Bd0A8fBD31f4D5002c34b98d0c328791c8",
"deposits": [
{
"amount": "12500",
"user": "0x52dD21Bd0A8fBD31f4D5002c34b98d0c328791c8",
"tranche_id": 55,
"tx": "0x3d02aec9b4c1ff084ae4518b6a6f4647487c2724afc02c33f7dcd378d606f93f"
}
],
"withdrawals": [],
"total_tokens": "12500",
"withdrawn_tokens": "0",
"remaining_tokens": "12500"
},
{
"address": "0xbCDBCC3Ff54D659f2CC737bEf49B10D92dF3FDbf",
"deposits": [
@@ -561,7 +530,7 @@
"tranche_end": "2023-04-06T00:00:00.000Z",
"total_added": "14099",
"total_removed": "165.10784124668",
"locked_amount": "3067.69057198327407086",
"locked_amount": "3863.2439127837516484",
"deposits": [
{
"amount": "30",
@@ -3349,7 +3318,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "86666.297",
"total_removed": "0",
"locked_amount": "59299.9407029960677967199",
"locked_amount": "59715.277169199897517339",
"deposits": [
{
"amount": "86666.297",
@@ -3415,7 +3384,7 @@
"tranche_end": "2023-06-01T00:00:00.000Z",
"total_added": "2500",
"total_removed": "0",
"locked_amount": "861.882504070004",
"locked_amount": "885.91015466015475",
"deposits": [
{
"amount": "2500",
@@ -3536,7 +3505,7 @@
"tranche_end": "2023-09-01T00:00:00.000Z",
"total_added": "17500",
"total_removed": "0",
"locked_amount": "14717.5995118760055",
"locked_amount": "14883.964875201289",
"deposits": [
{
"amount": "12500",
@@ -3802,8 +3771,8 @@
"tranche_start": "2023-02-01T00:00:00.000Z",
"tranche_end": "2023-08-01T00:00:00.000Z",
"total_added": "37500",
"total_removed": "11535.201330975",
"locked_amount": "25637.78583486801375",
"total_removed": "4574.865235275",
"locked_amount": "26000.1918354818925",
"deposits": [
{
"amount": "7500",
@@ -3827,11 +3796,6 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xe021c767a9587b28a6772b57666d72122e5d869c477596e246a4365ee6b7ce43"
},
{
"amount": "6960.3360957",
"user": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
"tx": "0x3f63318adc1797232c2578fa0f5eaccd21318427a3c243490817f778678bb6c6"
},
{
"amount": "92.587476975",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -4076,12 +4040,6 @@
}
],
"withdrawals": [
{
"amount": "6960.3360957",
"user": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
"tranche_id": 34,
"tx": "0x3f63318adc1797232c2578fa0f5eaccd21318427a3c243490817f778678bb6c6"
},
{
"amount": "2275.1131827",
"user": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
@@ -4090,8 +4048,8 @@
}
],
"total_tokens": "30000",
"withdrawn_tokens": "9235.4492784",
"remaining_tokens": "20764.5507216"
"withdrawn_tokens": "2275.1131827",
"remaining_tokens": "27724.8868173"
}
]
},
@@ -4101,7 +4059,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "129999.45",
"total_removed": "0",
"locked_amount": "59245.836968509227749328",
"locked_amount": "59660.7944924472825704535",
"deposits": [
{
"amount": "129999.45",
@@ -4167,7 +4125,7 @@
"tranche_end": "2023-09-03T00:00:00.000Z",
"total_added": "62600",
"total_removed": "0",
"locked_amount": "26882.8490360223239",
"locked_amount": "27182.851040081174176",
"deposits": [
{
"amount": "10000",
@@ -4360,7 +4318,7 @@
"tranche_end": "2023-09-17T00:00:00.000Z",
"total_added": "5000",
"total_removed": "0",
"locked_amount": "2338.973236935566",
"locked_amount": "2362.93505834601735",
"deposits": [
{
"amount": "5000",
@@ -4571,7 +4529,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "97499.58",
"total_removed": "0",
"locked_amount": "1336.84868966454578257644",
"locked_amount": "1743.88336560594536108964",
"deposits": [
{
"amount": "97499.58",
@@ -4604,7 +4562,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "135173.4239508",
"total_removed": "98230.390980249184455396",
"locked_amount": "1827.2413614734815961140086816",
"locked_amount": "2383.5874918801371561646812876",
"deposits": [
{
"amount": "135173.4239508",
@@ -4650,7 +4608,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "32499.86",
"total_removed": "0",
"locked_amount": "562.38915759984502962888",
"locked_amount": "733.62161665551011862912",
"deposits": [
{
"amount": "32499.86",
@@ -4683,7 +4641,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "10833.29",
"total_removed": "0",
"locked_amount": "183.052213503540805372",
"locked_amount": "238.78671732570820440756",
"deposits": [
{
"amount": "10833.29",
@@ -4716,7 +4674,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "22749.93",
"total_removed": "4720.860935375",
"locked_amount": "684.29005804973844628731",
"locked_amount": "892.6380814136124106908",
"deposits": [
{
"amount": "6500",
@@ -4868,7 +4826,7 @@
"tranche_end": "2023-05-01T00:00:00.000Z",
"total_added": "22500",
"total_removed": "6111.900993675",
"locked_amount": "3946.20741252302085",
"locked_amount": "4163.6510128913445",
"deposits": [
{
"amount": "7500",
@@ -5275,7 +5233,7 @@
"tranche_end": "2023-06-02T00:00:00.000Z",
"total_added": "1939928.38",
"total_removed": "928642.9598472029154",
"locked_amount": "338796.7791632851902753616",
"locked_amount": "348093.622641410450169508",
"deposits": [
{
"amount": "1852091.69",
@@ -38966,7 +38924,7 @@
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "3732368.4671",
"total_removed": "700133.348465855088393",
"locked_amount": "545114.0177930545133092967",
"locked_amount": "559400.02940181935737278844",
"deposits": [
{
"amount": "1998.95815",
@@ -40347,8 +40305,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "15870102.715470999700000001",
"total_removed": "812577.59329050683322952",
"locked_amount": "7232626.89306985865129106659442422357718304",
"total_removed": "812130.55546472109935452",
"locked_amount": "7283284.17298492326254788501911774103514463",
"deposits": [
{
"amount": "16249.93",
@@ -40862,11 +40820,6 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xa13046dbc8f011b7647728acbd7b9c6a67fb3869efc0e9e48c9590300345570a"
},
{
"amount": "447.037825785733875",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xe41c5aea235784efd3ce7c38abcaa73a915e4ad398fbd738c9cf76ee95487de4"
},
{
"amount": "545.4204142199725",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -42867,12 +42820,6 @@
"tranche_id": 2,
"tx": "0xa13046dbc8f011b7647728acbd7b9c6a67fb3869efc0e9e48c9590300345570a"
},
{
"amount": "447.037825785733875",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0xe41c5aea235784efd3ce7c38abcaa73a915e4ad398fbd738c9cf76ee95487de4"
},
{
"amount": "545.4204142199725",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -44249,8 +44196,8 @@
}
],
"total_tokens": "259998.8875",
"withdrawn_tokens": "141121.612888745726875",
"remaining_tokens": "118877.274611254273125"
"withdrawn_tokens": "140674.575062959993",
"remaining_tokens": "119324.312437040007"
},
{
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
@@ -46595,8 +46542,8 @@
"tranche_start": "2021-11-05T00:00:00.000Z",
"tranche_end": "2023-05-05T00:00:00.000Z",
"total_added": "14597706.0446472999",
"total_removed": "5790314.064810046934064816",
"locked_amount": "955669.740633044212659704752133556",
"total_removed": "5782575.169630789834713996",
"locked_amount": "1002436.218000846412796734272837213",
"deposits": [
{
"amount": "129284.449",
@@ -46820,16 +46767,6 @@
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x5c9bcf8195dc2bf6d36af74095f45cc5f8289d7239e4205d74f06419b042d648"
},
{
"amount": "7118.88831110397421632",
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
"tx": "0xbe429d608aa735a1bea0099ee9806e2b0a293262199fa9881a3672215e68a6c3"
},
{
"amount": "620.0068681531251345",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xa1dcf42aa5cdb34107d55521fd3b28c8dcea0a6a991ba7ec370f091c2a97a610"
},
{
"amount": "755.482067130393772",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -49972,12 +49909,6 @@
"tranche_id": 3,
"tx": "0x5c9bcf8195dc2bf6d36af74095f45cc5f8289d7239e4205d74f06419b042d648"
},
{
"amount": "620.0068681531251345",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0xa1dcf42aa5cdb34107d55521fd3b28c8dcea0a6a991ba7ec370f091c2a97a610"
},
{
"amount": "755.482067130393772",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -52656,8 +52587,8 @@
}
],
"total_tokens": "359123.469575",
"withdrawn_tokens": "335078.02995866618372525",
"remaining_tokens": "24045.43961633381627475"
"withdrawn_tokens": "334458.02309051305859075",
"remaining_tokens": "24665.44648448694140925"
},
{
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
@@ -52893,12 +52824,6 @@
"tranche_id": 3,
"tx": "0x4eb2ed2540197b432b08d7ed69ab17a69909e2055f645ce8a0922c1a29ffeec8"
},
{
"amount": "7118.88831110397421632",
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
"tranche_id": 3,
"tx": "0xbe429d608aa735a1bea0099ee9806e2b0a293262199fa9881a3672215e68a6c3"
},
{
"amount": "80421.5336580481619385",
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
@@ -53231,8 +53156,8 @@
}
],
"total_tokens": "1266324.603486",
"withdrawn_tokens": "1179718.62954110669784558",
"remaining_tokens": "86605.97394489330215442"
"withdrawn_tokens": "1172599.74123000272362926",
"remaining_tokens": "93724.86225599727637074"
},
{
"address": "0xC5d9221EB9c28A69859264c0A2Fe0d3272228296",
@@ -54061,7 +53986,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "5778205.3912159303",
"total_removed": "3381706.364737906998719578",
"locked_amount": "60687.4908264066119772663325364137",
"locked_amount": "79165.2088757254297160760025198165",
"deposits": [
{
"amount": "552496.6455",
@@ -56189,7 +56114,7 @@
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "472355.6199999996",
"total_removed": "38870.3290450237949",
"locked_amount": "86376.432123878662920840984880776",
"locked_amount": "88640.13232561127483282507204466",
"deposits": [
{
"amount": "3000",
@@ -39,7 +39,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
it('market volume displayed', () => {
cy.getByTestId(marketTitle).contains('Market volume').click();
validateMarketDataRow(0, '24 Hour Volume', '1');
validateMarketDataRow(1, 'Open Interest', '-');
validateMarketDataRow(1, 'Open Interest', '0');
validateMarketDataRow(2, 'Best Bid Volume', '1');
validateMarketDataRow(3, 'Best Offer Volume', '3');
validateMarketDataRow(4, 'Best Static Bid Volume', '2');
@@ -1,28 +0,0 @@
describe('chart', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('config should persist', () => {
cy.getByTestId('Chart').click();
cy.get('[data-testid="tab-chart"] button').as('control-buttons');
cy.get('@control-buttons').each(($button) => {
cy.wrap($button).click();
cy.get(
'[role="menuitemradio"]:first, [role="menuitemcheckbox"]:first'
).click();
});
cy.getByTestId('Depth').click();
cy.getByTestId('Chart').click();
cy.get('@control-buttons').each(($button) => {
cy.wrap($button).click();
cy.get('[role="menuitemradio"]:first, [role="menuitemcheckbox"]:first')
.within(($lastMenuItem) => {
expect($lastMenuItem.data('state')).to.equal('checked');
})
.click();
});
});
});
-1
View File
@@ -10,4 +10,3 @@ NX_VEGA_TOKEN_URL=https://token.fairground.wtf
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
-1
View File
@@ -11,7 +11,6 @@ NX_VEGA_URL=http://localhost:3028/query
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
-1
View File
@@ -10,5 +10,4 @@ NX_VEGA_TOKEN_URL=https://token.fairground.wtf
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
-1
View File
@@ -9,5 +9,4 @@ NX_VEGA_TOKEN_URL=https://token.vega.xyz
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
+13
View File
@@ -0,0 +1,13 @@
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
NX_VEGA_ENV=MIRROR
NX_VEGA_EXPLORER_URL=https://mainnet-mirror.explorer.vega.xyz
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://stagnet1.console.vega.xyz\",\"STAGNET3\":\"https://stagnet3.console.vega.xyz\"}
NX_VEGA_TOKEN_URL=https://mainnet-mirror.token.vega.xyz
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
+11
View File
@@ -0,0 +1,11 @@
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_HOSTED_WALLET_URL=https://wallet.sandbox.vega.xyz
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/sandbox/vegawallet-sandbox.toml
NX_VEGA_ENV=SANDBOX
NX_VEGA_NETWORKS={\"DEVNET\":\"https://dev.token.vega.xyz\",\"STAGNET3\":\"https://stagnet3.token.vega.xyz\",\"STAGNET1\":\"https://stagnet1.token.vega.xyz\",\"TESTNET\":\"https://token.fairground.wtf\",\"MAINNET\":\"https://token.vega.xyz\"}
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
+1 -2
View File
@@ -10,5 +10,4 @@ NX_VEGA_TOKEN_URL=https://stagnet1.token.vega.xyz
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
+1 -2
View File
@@ -10,5 +10,4 @@ NX_VEGA_TOKEN_URL=https://token.fairground.wtf
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
+1 -2
View File
@@ -10,5 +10,4 @@ NX_VEGA_TOKEN_URL=https://token.fairground.wtf
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
+1 -2
View File
@@ -10,5 +10,4 @@ NX_VEGA_TOKEN_URL=https://validator-testnet.governance.fairground.wtf
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
+28 -5
View File
@@ -1,16 +1,39 @@
import { AnnouncementBanner } from '@vegaprotocol/announcements';
import { useEnvironment } from '@vegaprotocol/environment';
import {
AnnouncementBanner,
ExternalLink,
Icon,
} from '@vegaprotocol/ui-toolkit';
import { useGlobalStore } from '../../stores';
import React from 'react';
export const Banner = () => {
const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
const { update, shouldDisplayAnnouncementBanner } = useGlobalStore(
(store) => ({
update: store.update,
shouldDisplayAnnouncementBanner: store.shouldDisplayAnnouncementBanner,
})
);
// Return an empty div so that the grid layout in _app.page.ts
// renders correctly
if (!ANNOUNCEMENTS_CONFIG_URL) {
if (!shouldDisplayAnnouncementBanner) {
return <div />;
}
return (
<AnnouncementBanner app="console" configUrl={ANNOUNCEMENTS_CONFIG_URL} />
<AnnouncementBanner>
<div className="grid grid-cols-[auto_1fr] gap-4 font-alpha calt uppercase text-center text-lg text-white">
<button
className="flex items-center"
onClick={() => update({ shouldDisplayAnnouncementBanner: false })}
>
<Icon name="cross" className="w-6 h-6" ariaLabel="dismiss" />
</button>
<div>
<span className="pr-4">Mainnet sim 3 is live!</span>
<ExternalLink href="https://fairground.wtf/">Learn more</ExternalLink>
</div>
</div>
</AnnouncementBanner>
);
};
+2
View File
@@ -7,6 +7,7 @@ interface GlobalStore {
marketId: string | null;
update: (store: Partial<Omit<GlobalStore, 'update'>>) => void;
shouldDisplayWelcomeDialog: boolean;
shouldDisplayAnnouncementBanner: boolean;
}
interface PageTitleStore {
@@ -18,6 +19,7 @@ export const useGlobalStore = create<GlobalStore>()((set) => ({
nodeSwitcherDialog: false,
marketId: LocalStorage.getItem('marketId') || null,
shouldDisplayWelcomeDialog: false,
shouldDisplayAnnouncementBanner: true,
update: (newState) => {
set(
produce((state: GlobalStore) => {
-4
View File
@@ -1,4 +0,0 @@
{
"presets": ["@nrwl/next/babel"],
"plugins": []
}
-18
View File
@@ -1,18 +0,0 @@
{
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
-28
View File
@@ -1,28 +0,0 @@
const rootMain = require('../../../.storybook/main');
module.exports = {
...rootMain,
core: { ...rootMain.core, builder: 'webpack5' },
stories: [
...rootMain.stories,
'../src/lib/**/*.stories.mdx',
'../src/lib/**/*.stories.@(js|jsx|ts|tsx)',
],
addons: [
...rootMain.addons,
'@nrwl/react/plugins/storybook',
'storybook-addon-themes',
],
webpackFinal: async (config, { configType }) => {
// apply any global webpack configs that might have been specified in .storybook/main.js
if (rootMain.webpackFinal) {
config = await rootMain.webpackFinal(config, { configType });
}
// add your own webpack tweaks if needed
return config;
},
};
@@ -1 +0,0 @@
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
-2
View File
@@ -1,2 +0,0 @@
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
export * from '../../ui-toolkit/.storybook/preview';
@@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@@ -1,20 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"emitDecoratorMetadata": true,
"outDir": ""
},
"files": [
"../../../node_modules/@nrwl/react/typings/styled-jsx.d.ts",
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../../node_modules/@nrwl/react/typings/image.d.ts"
],
"exclude": [
"../**/*.spec.ts",
"../**/*.spec.js",
"../**/*.spec.tsx",
"../**/*.spec.jsx",
"jest.config.ts"
],
"include": ["../src/**/*", "*.js"]
}
-11
View File
@@ -1,11 +0,0 @@
# announcements
This library was generated with [Nx](https://nx.dev).
## Creating announcements
The announcements config lives in the [announcements repo](https://github.com/vegaprotocol/announcements). To create app/env specific announcements, check out the readme in the repo!
## Running unit tests
Run `nx test announcements` to execute the unit tests via [Jest](https://jestjs.io).
-16
View File
@@ -1,16 +0,0 @@
/* eslint-disable */
export default {
displayName: 'announcements',
preset: '../../jest.preset.js',
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
},
},
transform: {
'^.+\\.[tj]sx?$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/libs/announcements',
setupFilesAfterEnv: ['./src/setup-tests.ts'],
};
-4
View File
@@ -1,4 +0,0 @@
{
"name": "@vegaprotocol/announcements",
"version": "0.0.1"
}
-81
View File
@@ -1,81 +0,0 @@
{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/announcements/src",
"projectType": "library",
"tags": [],
"targets": {
"build": {
"executor": "@nrwl/web:rollup",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/libs/accounts",
"tsConfig": "libs/announcements/tsconfig.lib.json",
"project": "libs/announcements/package.json",
"entryFile": "libs/announcements/src/index.ts",
"external": ["react/jsx-runtime"],
"rollupConfig": "@nrwl/react/plugins/bundle-rollup",
"compiler": "babel",
"assets": [
{
"glob": "libs/announcements/README.md",
"input": ".",
"output": "."
}
]
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/announcements/**/*.{ts,tsx,js,jsx}"]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["coverage/libs/announcements"],
"options": {
"jestConfig": "libs/announcements/jest.config.ts",
"passWithNoTests": true
}
},
"storybook": {
"executor": "@nrwl/storybook:storybook",
"options": {
"uiFramework": "@storybook/react",
"port": 4400,
"config": {
"configFolder": "libs/announcements/.storybook"
}
},
"configurations": {
"ci": {
"quiet": true
}
}
},
"build-storybook": {
"executor": "@nrwl/storybook:build",
"outputs": ["{options.outputPath}"],
"options": {
"uiFramework": "@storybook/react",
"outputPath": "dist/storybook/announcements",
"config": {
"configFolder": "libs/announcements/.storybook"
}
},
"configurations": {
"ci": {
"quiet": true
}
}
},
"build-spec": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "yarn tsc --project ./libs/announcements/tsconfig.spec.json"
}
}
}
}
-1
View File
@@ -1 +0,0 @@
export * from './lib';
@@ -1,207 +0,0 @@
import fetchMock from 'fetch-mock';
import { addDays } from 'date-fns';
import { act, render, waitFor } from '@testing-library/react';
import { AnnouncementBanner } from './announcements';
const MOCK_URL = 'http://somewhere.com/config.json';
const MOCK_ANNOUNCEMENT = {
text: 'Attention everyone!',
url: 'http://click.me/',
urlText: 'Read more',
};
describe('Announcements', () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
fetchMock.reset();
});
it('does not display the banner when fetching announcements fails', async () => {
fetchMock.get(MOCK_URL, 500);
const { container } = render(
<AnnouncementBanner app="console" configUrl={MOCK_URL} />
);
await waitFor(() => {
expect(container.firstChild).toBeEmptyDOMElement();
});
});
it('does not display the banner when there are no announcements', async () => {
fetchMock.get(MOCK_URL, {
console: [],
governance: [],
explorer: [],
wallet: [],
website: [],
});
const { container } = render(
<AnnouncementBanner app="console" configUrl={MOCK_URL} />
);
await waitFor(() => {
expect(container.firstChild).toBeEmptyDOMElement();
});
});
it('shows the correct announcement', async () => {
fetchMock.get(MOCK_URL, {
console: [
{
text: 'Console announcement',
},
],
governance: [
{
text: 'Governance announcement',
},
],
explorer: [
{
text: 'Explorer announcement',
},
],
wallet: [
{
text: 'Wallet announcement',
},
],
website: [
{
text: 'Website announcement',
},
],
});
const { rerender, findByText } = render(
<AnnouncementBanner app="console" configUrl={MOCK_URL} />
);
expect(await findByText('Console announcement')).toBeVisible();
rerender(<AnnouncementBanner app="governance" configUrl={MOCK_URL} />);
expect(await findByText('Governance announcement')).toBeVisible();
rerender(<AnnouncementBanner app="explorer" configUrl={MOCK_URL} />);
expect(await findByText('Explorer announcement')).toBeVisible();
rerender(<AnnouncementBanner app="wallet" configUrl={MOCK_URL} />);
expect(await findByText('Wallet announcement')).toBeVisible();
rerender(<AnnouncementBanner app="website" configUrl={MOCK_URL} />);
expect(await findByText('Website announcement')).toBeVisible();
});
it('shows the announcement link', async () => {
fetchMock.get(MOCK_URL, {
console: [MOCK_ANNOUNCEMENT],
governance: [],
explorer: [],
wallet: [],
website: [],
});
const { findByText, findByRole } = render(
<AnnouncementBanner app="console" configUrl={MOCK_URL} />
);
const text = await findByText(MOCK_ANNOUNCEMENT.text);
const link = (await findByRole('link')) as HTMLAnchorElement;
const linkText = await findByText(MOCK_ANNOUNCEMENT.urlText);
expect(text).toBeVisible();
expect(link).toBeVisible();
expect(link.href).toBe(MOCK_ANNOUNCEMENT.url);
expect(linkText).toBeVisible();
});
it('shows the first announcement', async () => {
fetchMock.get(MOCK_URL, {
console: [
{
text: 'First text',
},
{
text: 'Second text',
},
],
governance: [],
explorer: [],
wallet: [],
website: [],
});
const { queryByText } = render(
<AnnouncementBanner app="console" configUrl={MOCK_URL} />
);
await waitFor(() => {
expect(queryByText('First text')).toBeInTheDocument();
});
});
it('does not show expired announcements', async () => {
fetchMock.get(MOCK_URL, {
console: [
{
text: 'Expired text',
timing: {
to: new Date(0).toISOString(),
},
},
{
text: 'Live text',
},
],
governance: [],
explorer: [],
wallet: [],
website: [],
});
const { queryByText } = render(
<AnnouncementBanner app="console" configUrl={MOCK_URL} />
);
await waitFor(() => {
expect(queryByText('Live text')).toBeInTheDocument();
});
});
it('hides announcements after they expire', async () => {
const now = new Date();
const tomorrow = addDays(now, 1);
fetchMock.get(MOCK_URL, {
console: [
{
text: 'Live text',
timing: {
to: tomorrow.toISOString(),
},
},
],
governance: [],
explorer: [],
wallet: [],
website: [],
});
const { queryByText } = render(
<AnnouncementBanner app="console" configUrl={MOCK_URL} />
);
await waitFor(() => {
expect(queryByText('Live text')).toBeInTheDocument();
});
act(() => {
jest.runOnlyPendingTimers();
});
await waitFor(() => {
expect(queryByText('Live text')).not.toBeInTheDocument();
});
});
});
@@ -1,57 +0,0 @@
import fetchMock from 'fetch-mock';
import type { Story, Meta } from '@storybook/react';
import { AnnouncementBanner } from './announcements';
export default {
component: AnnouncementBanner,
title: 'AnnouncementBanner',
} as Meta;
const MOCK_URL = 'http://somewhere.com/config.json';
fetchMock.get(MOCK_URL, {
console: [
{
text: 'Console announcement',
url: 'http://vega.xyz',
urlText: 'Read more',
},
],
governance: [
{
text: 'Governance announcement',
url: 'http://vega.xyz',
urlText: 'Read more',
},
],
explorer: [
{
text: 'Explorer announcement',
url: 'http://vega.xyz',
urlText: 'Read more',
},
],
wallet: [
{
text: 'Wallet announcement',
url: 'http://vega.xyz',
urlText: 'Read more',
},
],
website: [
{
text: 'Website announcement',
url: 'http://vega.xyz',
urlText: 'Read more',
},
],
});
const Template: Story = (args) => (
<AnnouncementBanner app={args.app} configUrl={args.configUrl} />
);
export const Default = Template.bind({});
Default.args = {
configUrl: MOCK_URL,
app: 'console',
};
@@ -1,96 +0,0 @@
import { useEffect, useState } from 'react';
import type { AppNameType, Announcement } from './schema';
import { useAnnouncement } from './hooks/use-announcement';
import {
Icon,
AnnouncementBanner as Banner,
ExternalLink,
} from '@vegaprotocol/ui-toolkit';
export type AnnouncementBannerProps = {
app: AppNameType;
configUrl: string;
};
// run only if below the allowed maximum delay ~24.8 days (https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value)
const MAX_DELAY = 2147483648;
const doesStartInTheFuture = (now: Date, data: Announcement) => {
return data.timing?.from
? now < data.timing.from &&
data.timing.from.valueOf() - now.valueOf() < MAX_DELAY
: false;
};
const doesEndInTheFuture = (now: Date, data: Announcement) => {
return data.timing?.to
? now < data.timing.to &&
data.timing.to.valueOf() - now.valueOf() < MAX_DELAY
: false;
};
export const AnnouncementBanner = ({
app,
configUrl,
}: AnnouncementBannerProps) => {
const [isVisible, setVisible] = useState(false);
const { data, reload } = useAnnouncement(app, configUrl);
useEffect(() => {
const now = new Date();
let stampFrom: NodeJS.Timeout;
let stampTo: NodeJS.Timeout;
if (data) {
const startsInTheFuture = doesStartInTheFuture(now, data);
const endsInTheFuture = doesEndInTheFuture(now, data);
if (!startsInTheFuture) {
setVisible(true);
}
if (data.timing?.from && startsInTheFuture) {
stampFrom = setTimeout(() => {
setVisible(true);
}, data.timing.from.valueOf() - now.valueOf());
}
if (data.timing?.to && endsInTheFuture) {
stampTo = setTimeout(() => {
setVisible(false);
reload();
}, data.timing.to.valueOf() - now.valueOf());
}
}
return () => {
clearTimeout(stampFrom);
clearTimeout(stampTo);
};
}, [data, reload, setVisible]);
if (!data || !isVisible) {
return <div />;
}
return (
<Banner className="relative px-10">
<button
className="absolute left-0 top-0 w-10 h-full flex items-center justify-center"
data-testid="app-announcement-close"
onClick={() => setVisible(false)}
>
<Icon name="cross" className="w-6 h-6" ariaLabel="dismiss" />
</button>
<div
data-testid="app-announcement"
className="relative font-alpha flex gap-2 justify-center calt uppercase text-center text-lg text-white"
>
<span className="pr-4">{data.text}</span>
{data.urlText && data.url && (
<ExternalLink href={data.url}>{data.urlText}</ExternalLink>
)}
</div>
</Banner>
);
};
@@ -1,91 +0,0 @@
import fetchMock from 'fetch-mock';
import { renderHook, waitFor } from '@testing-library/react';
import { useAnnouncement } from './use-announcement';
const MOCK_URL = 'http://somewhere.com/config.json';
const MOCK_ANNOUNCEMENT = {
text: 'Attention everyone!',
url: 'http://click.me/',
urlText: 'Read more',
};
describe('Use announcement hook', () => {
afterEach(() => {
fetchMock.reset();
});
it('loads the data', async () => {
fetchMock.get(MOCK_URL, {
console: [MOCK_ANNOUNCEMENT],
governance: [],
explorer: [],
wallet: [],
});
const { result } = renderHook(() => useAnnouncement('console', MOCK_URL));
expect(result.current.loading).toBe(true);
expect(result.current.data).toEqual(null);
expect(result.current.error).toBe(null);
await waitFor(() => {
expect(result.current.loading).toBe(false);
expect(result.current.data).toEqual(MOCK_ANNOUNCEMENT);
expect(result.current.error).toBe(null);
});
});
it('returns an error when cannot load data', async () => {
fetchMock.get(MOCK_URL, 404);
const { result } = renderHook(() => useAnnouncement('console', MOCK_URL));
expect(result.current.loading).toBe(true);
expect(result.current.data).toEqual(null);
expect(result.current.error).toBe(null);
await waitFor(() => {
expect(result.current.loading).toBe(false);
expect(result.current.data).toBe(null);
expect(result.current.error).not.toBe(null);
});
});
it('returns an error when data is malformed', async () => {
fetchMock.get(MOCK_URL, {
some: 'json',
});
const { result } = renderHook(() => useAnnouncement('console', MOCK_URL));
expect(result.current.loading).toBe(true);
expect(result.current.data).toEqual(null);
expect(result.current.error).toBe(null);
await waitFor(() => {
expect(result.current.loading).toBe(false);
expect(result.current.data).toBe(null);
expect(result.current.error).not.toBe(null);
});
});
it('filters out expired announcements', async () => {
fetchMock.get(MOCK_URL, {
console: [
{
...MOCK_ANNOUNCEMENT,
timing: {
to: new Date(0).toISOString(),
},
},
],
governance: [],
explorer: [],
wallet: [],
});
const { result } = renderHook(() => useAnnouncement('console', MOCK_URL));
expect(result.current.loading).toBe(true);
expect(result.current.data).toEqual(null);
expect(result.current.error).toBe(null);
await waitFor(() => {
expect(result.current.loading).toBe(false);
expect(result.current.data).toBe(null);
expect(result.current.error).toBe(null);
});
});
});
@@ -1,77 +0,0 @@
import { useCallback, useEffect, useState } from 'react';
import type { AppNameType, Announcement } from '../schema';
import { AnnouncementsSchema } from '../schema';
const getData = async (name: AppNameType, url: string) => {
const now = new Date();
const response = await fetch(url);
const data = await response.json();
const parsed = AnnouncementsSchema.parse(data);
const list = parsed[name] || [];
const announcements = list
.filter((item) => {
// Don't add expired items
return !item.timing?.to || (item.timing.to && now < item.timing.to);
})
.sort((a, b) => {
const fromA = a.timing?.from || new Date(0);
const fromB = b.timing?.from || new Date(0);
// Sort by from date
return fromA.valueOf() - fromB.valueOf();
});
return announcements[0] || null;
};
type State = {
loading: boolean;
data: null | Announcement;
error: null | string;
};
export const useAnnouncement = (name: AppNameType, url: string) => {
const [state, setState] = useState<State>({
loading: true,
data: null,
error: null,
});
const fetchData = useCallback(() => {
let mounted = true;
getData(name, url)
.then((data) => {
if (mounted) {
setState({
loading: false,
data,
error: null,
});
}
})
.catch((err) => {
if (mounted) {
setState({
loading: false,
data: null,
error: `${err}`,
});
}
});
return () => {
mounted = false;
};
}, [name, url, setState]);
useEffect(() => {
fetchData();
}, [fetchData]);
return {
...state,
reload: fetchData,
};
};
-2
View File
@@ -1,2 +0,0 @@
export * from './announcements';
export * from './hooks/use-announcement';
-30
View File
@@ -1,30 +0,0 @@
import { z } from 'zod';
const AppName = z.enum([
'console',
'governance',
'explorer',
'wallet',
'website',
]);
export type AppNameType = z.infer<typeof AppName>;
export const AnnouncementSchema = z.object({
text: z.string(),
url: z.string().url().optional(),
urlText: z.string().optional(),
timing: z
.object({
from: z.coerce.date().optional(),
to: z.coerce.date().optional(),
})
.optional(),
});
export type Announcement = z.infer<typeof AnnouncementSchema>;
export const AnnouncementsSchema = z.record(
AppName,
z.array(AnnouncementSchema)
);
-1
View File
@@ -1 +0,0 @@
import '@testing-library/jest-dom';
-27
View File
@@ -1,27 +0,0 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
},
{
"path": "./.storybook/tsconfig.json"
}
]
}
-23
View File
@@ -1,23 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": ["node"]
},
"files": [
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../node_modules/@nrwl/next/typings/image.d.ts"
],
"exclude": [
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.test.tsx",
"**/*.spec.js",
"**/*.test.js",
"**/*.spec.jsx",
"**/*.test.jsx",
"jest.config.ts"
],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
}
-21
View File
@@ -1,21 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node", "@testing-library/jest-dom"]
},
"include": [
"**/*.test.ts",
"**/*.spec.ts",
"**/*.test.tsx",
"**/*.spec.tsx",
"**/*.test.js",
"**/*.spec.js",
"**/*.test.jsx",
"**/*.spec.jsx",
"**/*.d.ts",
"../react-helpers/src/lib/grid-cells/summary-row.spec.ts",
"jest.config.ts"
]
}
+12 -87
View File
@@ -12,13 +12,9 @@ import {
} from 'pennant';
import { VegaDataSource } from './data-source';
import { useApolloClient } from '@apollo/client';
import { useMemo } from 'react';
import { useMemo, useState } from 'react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import {
useThemeSwitcher,
getValidItem,
getValidSubset,
} from '@vegaprotocol/react-helpers';
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
import {
DropdownMenu,
DropdownMenuCheckboxItem,
@@ -32,54 +28,6 @@ import {
import type { IconName } from '@blueprintjs/icons';
import { IconNames } from '@blueprintjs/icons';
import { t } from '@vegaprotocol/i18n';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
interface StoredSettings {
interval?: Interval;
type?: ChartType;
overlays?: Overlay[];
studies?: Study[];
}
export const useCandlesChartSettings = create<
StoredSettings & {
merge: (settings: StoredSettings) => void;
setType: (type: ChartType) => void;
setInterval: (interval: Interval) => void;
setOverlays: (overlays: Overlay[]) => void;
setStudies: (studies: Study[]) => void;
}
>()(
persist(
immer((set) => ({
merge: (settings: StoredSettings) =>
set((state) => {
Object.assign(state, settings);
}),
setType: (type: ChartType) =>
set((state) => {
state.type = type;
}),
setInterval: (interval: Interval) =>
set((state) => {
state.interval = interval;
}),
setOverlays: (overlays: Overlay[]) =>
set((state) => {
state.overlays = overlays;
}),
setStudies: (studies: Study[]) =>
set((state) => {
state.studies = studies;
}),
})),
{
name: 'console-candles',
}
)
);
const chartTypeIcon = new Map<ChartType, IconName>([
[ChartType.AREA, IconNames.TIMELINE_AREA_CHART],
@@ -99,31 +47,10 @@ export const CandlesChartContainer = ({
const { pubKey } = useVegaWallet();
const { theme } = useThemeSwitcher();
const settings = useCandlesChartSettings();
const interval: Interval = getValidItem(
settings.interval,
Object.values(Interval),
Interval.I15M
);
const chartType: ChartType = getValidItem(
settings.type,
Object.values(ChartType),
ChartType.CANDLE
);
const overlays: Overlay[] = getValidSubset(
settings.overlays,
Object.values(Overlay),
[]
);
const studies: Study[] = getValidSubset(
settings.studies,
Object.values(Study),
[Study.VOLUME]
);
const [interval, setInterval] = useState<Interval>(Interval.I15M);
const [chartType, setChartType] = useState<ChartType>(ChartType.CANDLE);
const [overlays, setOverlays] = useState<Overlay[]>([]);
const [studies, setStudies] = useState<Study[]>([Study.VOLUME]);
const dataSource = useMemo(() => {
return new VegaDataSource(client, marketId, pubKey);
@@ -143,7 +70,7 @@ export const CandlesChartContainer = ({
<DropdownMenuRadioGroup
value={interval}
onValueChange={(value) => {
settings.setInterval(value as Interval);
setInterval(value as Interval);
}}
>
{Object.values(Interval).map((timeInterval) => (
@@ -170,7 +97,7 @@ export const CandlesChartContainer = ({
<DropdownMenuRadioGroup
value={chartType}
onValueChange={(value) => {
settings.setType(value as ChartType);
setChartType(value as ChartType);
}}
>
{Object.values(ChartType).map((type) => (
@@ -198,7 +125,7 @@ export const CandlesChartContainer = ({
? newOverlays.splice(index, 1)
: newOverlays.push(overlay);
settings.setOverlays(newOverlays);
setOverlays(newOverlays);
}}
>
{overlayLabels[overlay]}
@@ -223,7 +150,7 @@ export const CandlesChartContainer = ({
? newStudies.splice(index, 1)
: newStudies.push(study);
settings.setStudies(newStudies);
setStudies(newStudies);
}}
>
{studyLabels[study]}
@@ -249,10 +176,8 @@ export const CandlesChartContainer = ({
interval={interval}
theme={theme}
onOptionsChanged={(options) => {
settings.merge({
overlays: options.overlays,
studies: options.studies,
});
setOverlays(options.overlays ?? []);
setStudies(options.studies ?? []);
}}
/>
</div>
@@ -1,5 +1,4 @@
import { Tooltip } from '@vegaprotocol/ui-toolkit';
import classnames from 'classnames';
import type { ReactNode } from 'react';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { Market, MarketData } from '@vegaprotocol/market-list';
@@ -12,12 +11,9 @@ interface DealTicketFeeDetailsProps {
order: OrderSubmissionBody['orderSubmission'];
market: Market;
marketData: MarketData;
currentInitialMargin?: string;
currentMaintenanceMargin?: string;
estimatedInitialMargin: string;
estimatedTotalInitialMargin: string;
marginAccountBalance: string;
generalAccountBalance: string;
margin: string;
totalMargin: string;
balance: string;
}
export interface DealTicketFeeDetailProps {
@@ -49,22 +45,23 @@ export const DealTicketFeeDetails = ({
order,
market,
marketData,
...args
margin,
totalMargin,
balance,
}: DealTicketFeeDetailsProps) => {
const feeDetails = useFeeDealTicketDetails(order, market, marketData);
const details = getFeeDetailsValues({
...feeDetails,
...args,
margin,
totalMargin,
balance,
});
return (
<div>
{details.map(({ label, value, labelDescription, symbol, indent }) => (
{details.map(({ label, value, labelDescription, symbol }) => (
<div
key={typeof label === 'string' ? label : 'value-dropdown'}
className={classnames(
'text-xs mt-2 flex justify-between items-center gap-4 flex-wrap',
{ 'ml-2': indent }
)}
className="text-xs mt-2 flex justify-between items-center gap-4 flex-wrap"
>
<div>
<Tooltip description={labelDescription}>
@@ -42,9 +42,6 @@ import {
import { OrderTimeInForce, OrderType } from '@vegaprotocol/types';
import { useOrderForm } from '../../hooks/use-order-form';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { marketMarginDataProvider } from '@vegaprotocol/positions';
export interface DealTicketProps {
market: Market;
@@ -104,12 +101,6 @@ export const DealTicket = ({
const { margin, totalMargin } = useInitialMargin(market.id, normalizedOrder);
const { data: currentMargins } = useDataProvider({
dataProvider: marketMarginDataProvider,
variables: { marketId: market.id, partyId: pubKey || '' },
skip: !pubKey,
});
useEffect(() => {
if (!pubKey) {
setError('summary', {
@@ -305,12 +296,9 @@ export const DealTicket = ({
order={normalizedOrder}
market={market}
marketData={marketData}
estimatedInitialMargin={margin}
estimatedTotalInitialMargin={totalMargin}
currentInitialMargin={currentMargins?.initialLevel}
currentMaintenanceMargin={currentMargins?.maintenanceLevel}
marginAccountBalance={marginAccountBalance}
generalAccountBalance={generalAccountBalance}
margin={margin}
totalMargin={totalMargin}
balance={marginAccountBalance}
/>
</form>
</TinyScroll>
+2 -26
View File
@@ -10,36 +10,12 @@ export const EST_MARGIN_TOOLTIP_TEXT = (settlementAsset: string) =>
export const EST_TOTAL_MARGIN_TOOLTIP_TEXT = t(
'Estimated total margin that will cover open position, active orders and this order.'
);
export const MARGIN_ACCOUNT_TOOLTIP_TEXT = t('Margin account balance.');
export const MARGIN_ACCOUNT_TOOLTIP_TEXT = t('Margin account balance');
export const MARGIN_DIFF_TOOLTIP_TEXT = (settlementAsset: string) =>
t(
"The additional margin required for your new position (taking into account volume and open orders), compared to your current margin. Measured in the market's settlement asset (%s).",
[settlementAsset]
);
export const DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT = (
settlementAsset: string
) =>
t(
'To cover the required margin, this amount will be drawn from your general (%s) account.',
[settlementAsset]
);
export const TOTAL_MARGIN_AVAILABLE = (
generalAccountBalance: string,
marginAccountBalance: string,
marginMaintenance: string,
settlementAsset: string
) =>
t(
'Total margin available = general %s balance (%s) + margin balance (%s) - maintenance level (%s).',
[
settlementAsset,
`${generalAccountBalance} ${settlementAsset}`,
`${marginAccountBalance} ${settlementAsset}`,
`${marginMaintenance} ${settlementAsset}`,
]
);
export const CONTRACTS_MARGIN_TOOLTIP_TEXT = t(
'The number of contracts determines how many units of the futures contract to buy or sell. For example, this is similar to buying one share of a listed company. The value of 1 contract is equivalent to the price of the contract. For example, if the current price is $50, then one contract is worth $50.'
);
@@ -64,7 +40,7 @@ export const EST_SLIPPAGE = t(
);
export const ERROR_SIZE_DECIMAL = t(
'The size field accepts up to X decimal places.'
'The size field accepts up to X decimal places'
);
export enum MarketModeValidationType {
@@ -15,8 +15,6 @@ import {
NOTIONAL_SIZE_TOOLTIP_TEXT,
MARGIN_ACCOUNT_TOOLTIP_TEXT,
MARGIN_DIFF_TOOLTIP_TEXT,
DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT,
TOTAL_MARGIN_AVAILABLE,
} from '../constants';
import { useOrderCloseOut } from './use-order-closeout';
import { useMarketAccountBalance } from '@vegaprotocol/accounts';
@@ -87,32 +85,24 @@ export const useFeeDealTicketDetails = (
};
export interface FeeDetails {
generalAccountBalance?: string;
marginAccountBalance?: string;
balance: string;
market: Market;
assetSymbol: string;
notionalSize: string | null;
estCloseOut: string | null;
estimateOrder: EstimateOrderQuery['estimateOrder'] | undefined;
estimatedInitialMargin: string;
estimatedTotalInitialMargin: string;
currentInitialMargin?: string;
currentMaintenanceMargin?: string;
margin: string;
totalMargin: string;
}
export const getFeeDetailsValues = ({
marginAccountBalance,
generalAccountBalance,
balance,
assetSymbol,
estimateOrder,
market,
notionalSize,
estimatedTotalInitialMargin,
currentInitialMargin,
currentMaintenanceMargin,
totalMargin,
}: FeeDetails) => {
const totalBalance =
BigInt(generalAccountBalance || '0') + BigInt(marginAccountBalance || '0');
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const formatValueWithMarketDp = (
@@ -133,8 +123,7 @@ export const getFeeDetailsValues = ({
label: string;
value?: string | null;
symbol: string;
indent?: boolean;
labelDescription?: React.ReactNode;
labelDescription: React.ReactNode;
}[] = [
{
label: t('Notional'),
@@ -164,64 +153,38 @@ export const getFeeDetailsValues = ({
),
symbol: assetSymbol,
},
/*
{
label: t('Initial margin'),
value: margin && `~${formatValueWithAssetDp(margin)}`,
symbol: assetSymbol,
labelDescription: EST_MARGIN_TOOLTIP_TEXT(assetSymbol),
},
*/
{
label: t('Margin required'),
value: `~${formatValueWithAssetDp(
currentInitialMargin
? (
BigInt(estimatedTotalInitialMargin) - BigInt(currentInitialMargin)
).toString()
: estimatedTotalInitialMargin
balance
? (BigInt(totalMargin) - BigInt(balance)).toString()
: totalMargin
)}`,
symbol: assetSymbol,
labelDescription: MARGIN_DIFF_TOOLTIP_TEXT(assetSymbol),
},
];
if (totalBalance) {
const totalMarginAvailable = (
currentMaintenanceMargin
? totalBalance - BigInt(currentMaintenanceMargin)
: totalBalance
).toString();
details.push({
indent: true,
label: t('Total margin available'),
value: `~${formatValueWithAssetDp(totalMarginAvailable)}`,
symbol: assetSymbol,
labelDescription: TOTAL_MARGIN_AVAILABLE(
formatValueWithAssetDp(generalAccountBalance),
formatValueWithAssetDp(marginAccountBalance),
formatValueWithAssetDp(currentMaintenanceMargin),
assetSymbol
),
});
if (marginAccountBalance) {
const deductionFromCollateral =
BigInt(estimatedTotalInitialMargin) - BigInt(marginAccountBalance);
details.push({
indent: true,
label: t('Deduction from collateral'),
value: `~${formatValueWithAssetDp(
deductionFromCollateral > 0 ? deductionFromCollateral.toString() : '0'
)}`,
symbol: assetSymbol,
labelDescription: DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT(assetSymbol),
});
}
if (balance) {
details.push({
label: t('Projected margin'),
value: `~${formatValueWithAssetDp(estimatedTotalInitialMargin)}`,
value: `~${formatValueWithAssetDp(totalMargin)}`,
symbol: assetSymbol,
labelDescription: EST_TOTAL_MARGIN_TOOLTIP_TEXT,
});
}
details.push({
label: t('Current margin allocation'),
value: `${formatValueWithAssetDp(marginAccountBalance)}`,
value: balance
? `~${formatValueWithAssetDp(balance)}`
: `${formatValueWithAssetDp(balance)}`,
symbol: assetSymbol,
labelDescription: MARGIN_ACCOUNT_TOOLTIP_TEXT,
});
@@ -65,11 +65,5 @@ export const useInitialMargin = (
sellMargin > buyMargin ? sellMargin.toString() : buyMargin.toString();
}
return useMemo(
() => ({
totalMargin,
margin,
}),
[totalMargin, margin]
);
return useMemo(() => ({ totalMargin, margin }), [totalMargin, margin]);
};
@@ -285,7 +285,6 @@ function compileEnvVars() {
GIT_BRANCH: process.env['GIT_COMMIT_BRANCH'],
GIT_COMMIT_HASH: process.env['GIT_COMMIT_HASH'],
GIT_ORIGIN_URL: process.env['GIT_ORIGIN_URL'],
ANNOUNCEMENTS_CONFIG_URL: process.env['NX_ANNOUNCEMENTS_CONFIG_URL'],
VEGA_INCIDENT_URL: process.env['NX_VEGA_INCIDENT_URL'],
};
@@ -50,7 +50,6 @@ const schemaObject = {
MAINTENANCE_PAGE: z.optional(z.boolean()),
ETH_LOCAL_PROVIDER_URL: z.optional(z.string()),
ETH_WALLET_MNEMONIC: z.optional(z.string()),
ANNOUNCEMENTS_CONFIG_URL: z.optional(z.string()),
VEGA_INCIDENT_URL: z.optional(z.string()),
};

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