Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
824b1921e7 |
@@ -3,7 +3,7 @@ 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/test/announcements.json
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -4,4 +4,4 @@ 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/test/announcements.json
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
||||
|
||||
@@ -13,7 +13,7 @@ NX_LOCAL_PROVIDER_URL=http://localhost:8545/
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
|
||||
#Test configuration variables
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
generateFreeFormProposalTitle,
|
||||
getProposalIdFromList,
|
||||
getProposalInformationFromTable,
|
||||
getSortOrderOfSuppliedArray,
|
||||
getSubmittedProposalFromProposalList,
|
||||
goToMakeNewProposal,
|
||||
governanceProposalType,
|
||||
@@ -23,9 +24,9 @@ import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/stakin
|
||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
|
||||
|
||||
const proposalDetailsTitle = '[data-testid="proposal-title"]';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const voteStatus = '[data-testid="vote-status"]';
|
||||
const proposalClosingDate = '[data-testid="vote-details"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
|
||||
describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
@@ -44,8 +45,16 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
});
|
||||
|
||||
it('Newly created proposals list - proposals closest to closing date appear higher in list', function () {
|
||||
const minCloseDays = 2;
|
||||
const maxCloseDays = 3;
|
||||
|
||||
// 3001-VOTE-005
|
||||
const proposalDays = [364, 50, 2];
|
||||
const proposalDays = [
|
||||
minCloseDays + 1,
|
||||
maxCloseDays,
|
||||
minCloseDays + 3,
|
||||
minCloseDays + 2,
|
||||
];
|
||||
for (let index = 0; index < proposalDays.length; index++) {
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
enterRawProposalBody(
|
||||
@@ -55,12 +64,19 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
waitForProposalSync();
|
||||
}
|
||||
|
||||
const arrayOfProposals: string[] = [];
|
||||
|
||||
navigateTo(navigation.proposals);
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.get(proposalClosingDate).first().should('contain.text', 'year');
|
||||
cy.get(proposalClosingDate).should('contain.text', 'months');
|
||||
cy.get(proposalClosingDate).last().should('contain.text', 'days');
|
||||
});
|
||||
cy.get(proposalDetailsTitle)
|
||||
.each((proposalTitleElement) => {
|
||||
arrayOfProposals.push(proposalTitleElement.text());
|
||||
})
|
||||
.then(() => {
|
||||
cy.wrap(getSortOrderOfSuppliedArray(arrayOfProposals)).should(
|
||||
'equal',
|
||||
'descending'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('Newly created proposals list - able to filter by proposerID to show it in list', function () {
|
||||
|
||||
@@ -15,13 +15,11 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should display announcement banner', function () {
|
||||
it('should display announcement banner', function () {
|
||||
cy.getByTestId('app-announcement')
|
||||
.should('contain.text', 'TEST ANNOUNCEMENT!')
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href', 'https://fairground.wtf')
|
||||
.and('have.text', 'CLICK LINK');
|
||||
cy.getByTestId('external-link').should('exist');
|
||||
});
|
||||
cy.getByTestId('app-announcement-close').should('be.visible').click();
|
||||
cy.getByTestId('app-announcement').should('not.exist');
|
||||
|
||||
@@ -333,7 +333,6 @@ context(
|
||||
.parent()
|
||||
.siblings()
|
||||
.invoke('text')
|
||||
.should('have.length.above', 3)
|
||||
.then((el) => {
|
||||
const value = parseFloat(el);
|
||||
cy.wrap(value).should('be.gte', parseFloat(expectedAmount));
|
||||
|
||||
@@ -150,6 +150,18 @@ export function waitForProposalSync() {
|
||||
});
|
||||
}
|
||||
|
||||
export function getSortOrderOfSuppliedArray(suppliedArray: string[]) {
|
||||
const tempArray = [];
|
||||
for (let index = 1; index < suppliedArray.length; index++) {
|
||||
tempArray.push(
|
||||
suppliedArray[index - 1].localeCompare(suppliedArray[index])
|
||||
);
|
||||
}
|
||||
if (tempArray.every((n) => n <= 0)) return 'ascending';
|
||||
else if (tempArray.every((n) => n >= 0)) return 'descending';
|
||||
else return 'unsorted';
|
||||
}
|
||||
|
||||
export function goToMakeNewProposal(proposalType: string) {
|
||||
navigateTo(navigation.proposals);
|
||||
cy.get(newProposalButton).should('be.visible').click();
|
||||
|
||||
@@ -105,25 +105,24 @@ async function vegaWalletTeardownStaking(stakingBridgeContract: StakingBridge) {
|
||||
{ timeout: transactionTimeout, log: false }
|
||||
).then((stakeBalance) => {
|
||||
if (Number(stakeBalance) != 0) {
|
||||
cy.get(vegaWalletContainer).within(() => {
|
||||
cy.getByTestId('currency-value')
|
||||
.invoke('text')
|
||||
.then(($associatedAmount) => {
|
||||
cy.wrap(
|
||||
stakingBridgeContract.remove_stake(
|
||||
String(stakeBalance),
|
||||
vegaWalletPubKey
|
||||
),
|
||||
{ timeout: transactionTimeout, log: false }
|
||||
);
|
||||
cy.get("[data-testid='currency-value']")
|
||||
.first()
|
||||
.invoke('text', {
|
||||
cy.get('[data-testid="vega-wallet-balance-unstaked"]:visible').within(
|
||||
() => {
|
||||
cy.get(associatedAmountInWallet)
|
||||
.invoke('text')
|
||||
.then(($walletAmount) => {
|
||||
cy.wrap(
|
||||
stakingBridgeContract.remove_stake(
|
||||
String(stakeBalance),
|
||||
vegaWalletPubKey
|
||||
),
|
||||
{ timeout: transactionTimeout, log: false }
|
||||
);
|
||||
cy.get(associatedAmountInWallet, {
|
||||
timeout: transactionTimeout,
|
||||
})
|
||||
.should('not.eq', $associatedAmount);
|
||||
});
|
||||
});
|
||||
}).should('not.have.text', $walletAmount);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -135,6 +134,8 @@ 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.wrap(
|
||||
vestingContract.remove_stake(String(vestingAmount), vegaWalletPubKey),
|
||||
{ timeout: transactionTimeout, log: false }
|
||||
|
||||
@@ -5,7 +5,7 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_FAIRGROUND=false
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_CONFIG_URL=''
|
||||
|
||||
NX_VEGA_URL=http://localhost:3028/query
|
||||
|
||||
@@ -595,7 +595,6 @@
|
||||
"noPercentage": "No percentage",
|
||||
"proposalTerms": "Proposal terms",
|
||||
"currentlySetTo": "Currently expected to ",
|
||||
"currently": "currently",
|
||||
"finalOutcomeMayDiffer": "Final outcome may differ",
|
||||
"votingPower": "Voting power",
|
||||
"normalisedVotingPower": "Normalised voting power",
|
||||
@@ -768,7 +767,7 @@
|
||||
"performancePenalty": "Performance penalty",
|
||||
"overstaked": "Overstaked",
|
||||
"overstakedPenalty": "Overstaked penalty",
|
||||
"homeProposalsIntro": "Decisions on the Vega network are on-chain, with tokenholders creating proposals that other tokenholders vote to approve or reject. Network upgrades are proposed and approved by validators.",
|
||||
"homeProposalsIntro": "Decisions on the Vega network are on-chain, with tokenholders creating proposals that other tokenholders vote to approve or reject.",
|
||||
"homeProposalsButtonText": "Browse, vote, and propose",
|
||||
"homeValidatorsIntro": "Vega runs on a delegated proof of stake blockchain, where validators earn fees for validating block transactions. Tokenholders can nominate validators by staking tokens to them.",
|
||||
"homeValidatorsButtonText": "Browse, and stake",
|
||||
@@ -776,18 +775,5 @@
|
||||
"homeRewardsButtonText": "See rewards",
|
||||
"homeVegaTokenIntro": "VEGA Token is a governance asset used to make and vote on proposals, and nominate validators.",
|
||||
"homeVegaTokenButtonText": "Manage tokens",
|
||||
"downloadProposalJson": "Download proposal as JSON",
|
||||
"networkUpgrade": "Network Upgrade",
|
||||
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED": "Approved",
|
||||
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING": "Pending",
|
||||
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED": "Rejected",
|
||||
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_UNSPECIFIED": "Unspecified",
|
||||
"vegaRelease{release}": "Vega Release {{release}}",
|
||||
"upgradeBlockHeight": "Upgrade block height",
|
||||
"vegaReleaseTag": "Vega release tag",
|
||||
"approvalStatus": "Approval status",
|
||||
"approvers": "Approvers",
|
||||
"approval (% validator voting power)": "approval (% validator voting power)",
|
||||
"67% voting power required": "67% voting power required",
|
||||
"Token": "Token"
|
||||
"downloadProposalJson": "Download proposal as JSON"
|
||||
}
|
||||
|
||||
@@ -10,31 +10,23 @@ import {
|
||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||
import { useRefreshAfterEpoch } from '../../hooks/use-refresh-after-epoch';
|
||||
import { ProposalsListItem } from '../proposals/components/proposals-list-item';
|
||||
import { ProtocolUpgradeProposalsListItem } from '../proposals/components/protocol-upgrade-proposals-list-item/protocol-upgrade-proposals-list-item';
|
||||
import Routes from '../routes';
|
||||
import { ExternalLinks, removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
import { useNodesQuery } from '../staking/home/__generated__/Nodes';
|
||||
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
|
||||
import { useProtocolUpgradesQuery } from '../proposals/protocol-upgrade/__generated__/ProtocolUpgradeProposals';
|
||||
import {
|
||||
getNotRejectedProposals,
|
||||
getNotRejectedProtocolUpgradeProposals,
|
||||
} from '../proposals/proposals/proposals-container';
|
||||
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 { ProtocolUpgradeProposalFieldsFragment } from '../proposals/protocol-upgrade/__generated__/ProtocolUpgradeProposals';
|
||||
|
||||
const nodesToShow = 6;
|
||||
|
||||
const HomeProposals = ({
|
||||
proposals,
|
||||
protocolUpgradeProposals,
|
||||
}: {
|
||||
proposals: ProposalFieldsFragment[];
|
||||
protocolUpgradeProposals: ProtocolUpgradeProposalFieldsFragment[];
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -55,10 +47,6 @@ const HomeProposals = ({
|
||||
data-testid="home-proposal-list"
|
||||
className="grid md:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2 gap-6"
|
||||
>
|
||||
{protocolUpgradeProposals.map((proposal, index) => (
|
||||
<ProtocolUpgradeProposalsListItem key={index} proposal={proposal} />
|
||||
))}
|
||||
|
||||
{proposals.map((proposal) => (
|
||||
<ProposalsListItem key={proposal.id} proposal={proposal} />
|
||||
))}
|
||||
@@ -119,7 +107,20 @@ const HomeNodes = ({
|
||||
|
||||
{trimmedActiveNodes.map(({ id, avatarUrl, name }) => (
|
||||
<div key={id} data-testid="validators" className="col-span-2">
|
||||
<ValidatorDetailsLink id={id} avatarUrl={avatarUrl} name={name} />
|
||||
<Link to={`${Routes.VALIDATORS}/${id}`}>
|
||||
<RoundedWrapper paddingBottom={true} border={false}>
|
||||
<div className="flex items-center justify-center m-[-1rem] p-4 bg-neutral-900 hover:bg-neutral-800">
|
||||
{avatarUrl && (
|
||||
<img
|
||||
className="h-6 w-6 rounded-full mr-2"
|
||||
src={avatarUrl}
|
||||
alt={`Avatar icon for ${name}`}
|
||||
/>
|
||||
)}
|
||||
<span className="text-sm">{name}</span>
|
||||
</div>
|
||||
</RoundedWrapper>
|
||||
</Link>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -135,35 +136,6 @@ const HomeNodes = ({
|
||||
);
|
||||
};
|
||||
|
||||
interface ValidatorDetailsLinkProps {
|
||||
id: string;
|
||||
avatarUrl: string | null | undefined;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const ValidatorDetailsLink = ({
|
||||
id,
|
||||
avatarUrl,
|
||||
name,
|
||||
}: ValidatorDetailsLinkProps) => {
|
||||
return (
|
||||
<Link to={`${Routes.VALIDATORS}/${id}`}>
|
||||
<RoundedWrapper paddingBottom={true} border={false}>
|
||||
<div className="flex items-center justify-center m-[-1rem] p-3 bg-neutral-900 hover:bg-neutral-800">
|
||||
{avatarUrl && (
|
||||
<img
|
||||
className="h-6 w-6 rounded-full mr-2"
|
||||
src={avatarUrl}
|
||||
alt={`Avatar icon for ${name}`}
|
||||
/>
|
||||
)}
|
||||
<span className="text-sm">{name}</span>
|
||||
</div>
|
||||
</RoundedWrapper>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const GovernanceHome = ({ name }: RouteChildProps) => {
|
||||
useDocumentTitle(name);
|
||||
const { t } = useTranslation();
|
||||
@@ -177,16 +149,6 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
|
||||
errorPolicy: 'ignore',
|
||||
});
|
||||
|
||||
const {
|
||||
data: protocolUpgradesData,
|
||||
loading: protocolUpgradesLoading,
|
||||
error: protocolUpgradesError,
|
||||
} = useProtocolUpgradesQuery({
|
||||
pollInterval: 5000,
|
||||
fetchPolicy: 'network-only',
|
||||
errorPolicy: 'ignore',
|
||||
});
|
||||
|
||||
const {
|
||||
data: validatorsData,
|
||||
error: validatorsError,
|
||||
@@ -201,38 +163,11 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
|
||||
proposalsData
|
||||
? getNotRejectedProposals<ProposalFieldsFragment>(
|
||||
proposalsData.proposalsConnection
|
||||
)
|
||||
).slice(0, 3)
|
||||
: [],
|
||||
[proposalsData]
|
||||
);
|
||||
|
||||
const protocolUpgradeProposals = useMemo(
|
||||
() =>
|
||||
protocolUpgradesData
|
||||
? getNotRejectedProtocolUpgradeProposals<ProtocolUpgradeProposalFieldsFragment>(
|
||||
protocolUpgradesData.protocolUpgradeProposals
|
||||
).filter(
|
||||
(p) =>
|
||||
Number(p.upgradeBlockHeight) >
|
||||
Number(protocolUpgradesData.lastBlockHeight)
|
||||
)
|
||||
: [],
|
||||
[protocolUpgradesData]
|
||||
);
|
||||
|
||||
const totalProposalsDesired = 4;
|
||||
const protocolUpgradeProposalsToShow = protocolUpgradeProposals.slice(
|
||||
0,
|
||||
totalProposalsDesired
|
||||
);
|
||||
const proposalsToShow =
|
||||
protocolUpgradeProposalsToShow.length === totalProposalsDesired
|
||||
? []
|
||||
: proposals.slice(
|
||||
0,
|
||||
totalProposalsDesired - protocolUpgradeProposalsToShow.length
|
||||
);
|
||||
|
||||
const activeNodes = removePaginationWrapper(
|
||||
validatorsData?.nodesConnection.edges
|
||||
);
|
||||
@@ -247,14 +182,11 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
|
||||
|
||||
return (
|
||||
<AsyncRenderer
|
||||
loading={proposalsLoading || protocolUpgradesLoading || validatorsLoading}
|
||||
error={proposalsError || protocolUpgradesError || validatorsError}
|
||||
data={proposalsData && protocolUpgradesData && validatorsData}
|
||||
loading={proposalsLoading || validatorsLoading}
|
||||
error={proposalsError || validatorsError}
|
||||
data={proposalsData && validatorsData}
|
||||
>
|
||||
<HomeProposals
|
||||
proposals={proposalsToShow}
|
||||
protocolUpgradeProposals={protocolUpgradeProposalsToShow}
|
||||
/>
|
||||
<HomeProposals proposals={proposals} />
|
||||
|
||||
<HomeNodes
|
||||
activeNodes={activeNodes}
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ const renderComponent = (proposals: ProposalQuery['proposal'][]) => (
|
||||
<MockedProvider mocks={[networkParamsQueryMock]}>
|
||||
<AppStateProvider>
|
||||
<VegaWalletContext.Provider value={mockWalletContext}>
|
||||
<ProposalsList proposals={proposals} protocolUpgradeProposals={[]} />
|
||||
<ProposalsList proposals={proposals} />
|
||||
</VegaWalletContext.Provider>
|
||||
</AppStateProvider>
|
||||
</MockedProvider>
|
||||
|
||||
@@ -3,21 +3,17 @@ import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Heading, SubHeading } from '../../../../components/heading';
|
||||
import { ProposalsListItem } from '../proposals-list-item';
|
||||
import { ProtocolUpgradeProposalsListItem } from '../protocol-upgrade-proposals-list-item/protocol-upgrade-proposals-list-item';
|
||||
import { ProposalsListFilter } from '../proposals-list-filter';
|
||||
import Routes from '../../../routes';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ExternalLinks } from '@vegaprotocol/utils';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from '../../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
|
||||
import { ExternalLinks } from '@vegaprotocol/utils';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
interface ProposalsListProps {
|
||||
proposals: Array<ProposalFieldsFragment | ProposalQuery['proposal']>;
|
||||
protocolUpgradeProposals: ProtocolUpgradeProposalFieldsFragment[];
|
||||
lastBlockHeight?: string;
|
||||
}
|
||||
|
||||
interface SortedProposalsProps {
|
||||
@@ -25,16 +21,7 @@ interface SortedProposalsProps {
|
||||
closed: Array<ProposalFieldsFragment | ProposalQuery['proposal']>;
|
||||
}
|
||||
|
||||
interface SortedProtocolUpgradeProposalsProps {
|
||||
open: ProtocolUpgradeProposalFieldsFragment[];
|
||||
closed: ProtocolUpgradeProposalFieldsFragment[];
|
||||
}
|
||||
|
||||
export const ProposalsList = ({
|
||||
proposals,
|
||||
protocolUpgradeProposals,
|
||||
lastBlockHeight,
|
||||
}: ProposalsListProps) => {
|
||||
export const ProposalsList = ({ proposals }: ProposalsListProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [filterString, setFilterString] = useState('');
|
||||
const sortedProposals = proposals.reduce(
|
||||
@@ -52,21 +39,6 @@ export const ProposalsList = ({
|
||||
}
|
||||
);
|
||||
|
||||
const sortedProtocolUpgradeProposals = protocolUpgradeProposals.reduce(
|
||||
(acc: SortedProtocolUpgradeProposalsProps, proposal) => {
|
||||
if (Number(proposal?.upgradeBlockHeight) > Number(lastBlockHeight)) {
|
||||
acc.open.push(proposal);
|
||||
} else {
|
||||
acc.closed.push(proposal);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
open: [],
|
||||
closed: [],
|
||||
}
|
||||
);
|
||||
|
||||
const filterPredicate = (
|
||||
p: ProposalFieldsFragment | ProposalQuery['proposal']
|
||||
) =>
|
||||
@@ -93,7 +65,7 @@ export const ProposalsList = ({
|
||||
</div>
|
||||
<p className="mb-8">
|
||||
{t(
|
||||
`The Vega network is governed by the community. View active proposals, vote on them or propose changes to the network. Network upgrades are proposed and approved by validators.`
|
||||
`The Vega network is governed by the community. View active proposals, vote on them or propose changes to the network.`
|
||||
)}{' '}
|
||||
<ExternalLink
|
||||
data-testid="proposal-documentation-link"
|
||||
@@ -108,15 +80,8 @@ export const ProposalsList = ({
|
||||
)}
|
||||
<section className="-mx-4 p-4 mb-8 bg-neutral-800">
|
||||
<SubHeading title={t('openProposals')} />
|
||||
{sortedProposals.open.length > 0 ||
|
||||
sortedProtocolUpgradeProposals.open.length > 0 ? (
|
||||
{sortedProposals.open.length > 0 ? (
|
||||
<ul data-testid="open-proposals">
|
||||
{sortedProtocolUpgradeProposals.open.map((proposal) => (
|
||||
<ProtocolUpgradeProposalsListItem
|
||||
key={proposal.upgradeBlockHeight}
|
||||
proposal={proposal}
|
||||
/>
|
||||
))}
|
||||
{sortedProposals.open.filter(filterPredicate).map((proposal) => (
|
||||
<ProposalsListItem key={proposal?.id} proposal={proposal} />
|
||||
))}
|
||||
@@ -129,16 +94,8 @@ export const ProposalsList = ({
|
||||
</section>
|
||||
<section>
|
||||
<SubHeading title={t('closedProposals')} />
|
||||
{sortedProposals.closed.length > 0 ||
|
||||
sortedProtocolUpgradeProposals.closed.length > 0 ? (
|
||||
{sortedProposals.closed.length > 0 ? (
|
||||
<ul data-testid="closed-proposals">
|
||||
{sortedProtocolUpgradeProposals.closed.map((proposal) => (
|
||||
<ProtocolUpgradeProposalsListItem
|
||||
key={proposal.upgradeBlockHeight}
|
||||
proposal={proposal}
|
||||
/>
|
||||
))}
|
||||
|
||||
{sortedProposals.closed.filter(filterPredicate).map((proposal) => (
|
||||
<ProposalsListItem key={proposal?.id} proposal={proposal} />
|
||||
))}
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from './protocol-update-proposal-detail-approvals';
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
RoundedWrapper,
|
||||
KeyValueTable,
|
||||
KeyValueTableRow,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { ValidatorDetailsLink } from '../../../home';
|
||||
import { getNormalisedVotingPower } from '../../../staking/shared';
|
||||
import type { NodesFragmentFragment } from '../../../staking/home/__generated__/Nodes';
|
||||
|
||||
export interface ProtocolUpdateProposalDetailApprovalsProps {
|
||||
totalConsensusValidators: number;
|
||||
// Consensus validators that have approved the proposal
|
||||
consensusApprovals: NodesFragmentFragment[];
|
||||
consensusApprovalsVotingPowerPercentage: string;
|
||||
}
|
||||
|
||||
export const ProtocolUpdateProposalDetailApprovals = ({
|
||||
totalConsensusValidators,
|
||||
consensusApprovals,
|
||||
consensusApprovalsVotingPowerPercentage,
|
||||
}: ProtocolUpdateProposalDetailApprovalsProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-10">
|
||||
<SubHeading title={t('approvalStatus')} />
|
||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||
<KeyValueTable data-testid="protocol-upgrade-approval-status">
|
||||
<KeyValueTableRow noBorder={true}>
|
||||
<span>{`${consensusApprovalsVotingPowerPercentage} ${t(
|
||||
'approval (% validator voting power)'
|
||||
)}`}</span>
|
||||
<span>({t('67% voting power required')})</span>
|
||||
</KeyValueTableRow>
|
||||
</KeyValueTable>
|
||||
</RoundedWrapper>
|
||||
</div>
|
||||
|
||||
<div className="mb-10">
|
||||
<SubHeading
|
||||
title={`${t('approvers')} (${
|
||||
consensusApprovals.length
|
||||
}/${totalConsensusValidators} validators)`}
|
||||
/>
|
||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||
<KeyValueTable data-testid="protocol-upgrade-approvers">
|
||||
<KeyValueTableRow>
|
||||
<div className="mb-2">{t('validator')}</div>
|
||||
<div className="text-white mb-2">{t('votingPower')}</div>
|
||||
</KeyValueTableRow>
|
||||
|
||||
{consensusApprovals.map((validator, index) => (
|
||||
<KeyValueTableRow
|
||||
noBorder={index === consensusApprovals?.length - 1}
|
||||
key={validator.pubkey}
|
||||
>
|
||||
<div
|
||||
className="-mb-3 mt-1"
|
||||
data-testid={`validator-${validator.id}`}
|
||||
>
|
||||
<ValidatorDetailsLink
|
||||
id={validator.id}
|
||||
avatarUrl={validator.avatarUrl}
|
||||
name={validator.name}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{getNormalisedVotingPower(
|
||||
validator.rankingScore.votingPower,
|
||||
2
|
||||
)}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
))}
|
||||
</KeyValueTable>
|
||||
</RoundedWrapper>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { ProtocolUpdateProposalDetailApprovals } from './protocol-update-proposal-detail-approvals';
|
||||
import { getNormalisedVotingPower } from '../../../staking/shared';
|
||||
import type { ProtocolUpdateProposalDetailApprovalsProps } from './protocol-update-proposal-detail-approvals';
|
||||
import type { NodesFragmentFragment } from '../../../staking/home/__generated__/Nodes';
|
||||
|
||||
describe('ProtocolUpdateProposalDetailApprovals', () => {
|
||||
const mockValidators: NodesFragmentFragment[] = [
|
||||
{
|
||||
id: 'ccc022b7e63a4d0a6d3a193c3940c88574060e58a184964c994998d86835a1b4',
|
||||
name: 'Marvin',
|
||||
avatarUrl:
|
||||
'https://upload.wikimedia.org/wikipedia/en/2/25/Marvin-TV-3.jpg',
|
||||
pubkey:
|
||||
'6abc23391a9f888ab240415bf63d6844b03fc360be822f4a1d2cd832d87b2917',
|
||||
stakedTotal: '14182454495731682635157',
|
||||
stakedByOperator: '1000000000000000000000',
|
||||
stakedByDelegates: '13182454495731682635157',
|
||||
pendingStake: '0',
|
||||
rankingScore: {
|
||||
rankingScore: '0.67845061012234727427532760837568',
|
||||
stakeScore: '0.3392701644525644',
|
||||
performanceScore: '0.9998677767864936',
|
||||
votingPower: '3500',
|
||||
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
__typename: 'RankingScore',
|
||||
},
|
||||
__typename: 'Node',
|
||||
},
|
||||
];
|
||||
|
||||
const defaultProps = {
|
||||
totalConsensusValidators: 3,
|
||||
consensusApprovals: mockValidators,
|
||||
consensusApprovalsVotingPowerPercentage: '75%',
|
||||
};
|
||||
|
||||
const renderComponent = (
|
||||
props: Partial<ProtocolUpdateProposalDetailApprovalsProps> = {}
|
||||
) => {
|
||||
const mergedProps = {
|
||||
...defaultProps,
|
||||
...props,
|
||||
};
|
||||
return render(
|
||||
<BrowserRouter>
|
||||
<ProtocolUpdateProposalDetailApprovals {...mergedProps} />
|
||||
</BrowserRouter>
|
||||
);
|
||||
};
|
||||
|
||||
it('renders without crashing', () => {
|
||||
renderComponent();
|
||||
expect(
|
||||
screen.getByTestId('protocol-upgrade-approval-status')
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByTestId('protocol-upgrade-approvers')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the correct number of consensus approvers', () => {
|
||||
renderComponent();
|
||||
const validators = screen.getAllByTestId(/validator-/i);
|
||||
expect(validators.length).toBe(mockValidators.length);
|
||||
});
|
||||
|
||||
it('renders the correct approval status with the required percentage', () => {
|
||||
renderComponent();
|
||||
expect(screen.getByText(/75% approval/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/67% voting power required/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the correct voting power for each validator', () => {
|
||||
renderComponent();
|
||||
mockValidators.forEach((validator) => {
|
||||
const normalisedVotingPower = getNormalisedVotingPower(
|
||||
validator.rankingScore.votingPower,
|
||||
2
|
||||
);
|
||||
expect(screen.getByText(normalisedVotingPower)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from './protocol-upgrade-proposal-detail-header';
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { ProtocolUpgradeProposalDetailHeader } from './protocol-upgrade-proposal-detail-header';
|
||||
|
||||
describe('ProtocolUpgradeProposalDetailHeader', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(
|
||||
<ProtocolUpgradeProposalDetailHeader releaseTag="v1.0.0" />
|
||||
);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render the release tag', () => {
|
||||
const { getByText } = render(
|
||||
<ProtocolUpgradeProposalDetailHeader releaseTag="v1.0.0" />
|
||||
);
|
||||
expect(getByText('Vega Release v1.0.0')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Intent, Lozenge } from '@vegaprotocol/ui-toolkit';
|
||||
import { Heading } from '../../../../components/heading';
|
||||
|
||||
export interface ProtocolUpgradeProposalDetailHeaderProps {
|
||||
releaseTag: string;
|
||||
}
|
||||
|
||||
export const ProtocolUpgradeProposalDetailHeader = ({
|
||||
releaseTag,
|
||||
}: ProtocolUpgradeProposalDetailHeaderProps) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<Heading title={t('vegaRelease{release}', { release: releaseTag })} />
|
||||
<div className="mb-10">
|
||||
<Lozenge variant={Intent.Success}>{t('networkUpgrade')}</Lozenge>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from './protocol-upgrade-proposal-detail-info';
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
// jest tests for the protocol upgrade proposal detail info component
|
||||
|
||||
import { render } from '@testing-library/react';
|
||||
import { ProtocolUpgradeProposalStatus } from '@vegaprotocol/types';
|
||||
import { ProtocolUpgradeProposalDetailInfo } from './protocol-upgrade-proposal-detail-info';
|
||||
|
||||
const renderComponent = () =>
|
||||
render(
|
||||
<ProtocolUpgradeProposalDetailInfo
|
||||
proposal={{
|
||||
vegaReleaseTag: 'v0.1.234',
|
||||
status:
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING,
|
||||
upgradeBlockHeight: '12345',
|
||||
approvers: [],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
describe('ProtocolUpgradeProposalDetailInfo', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = renderComponent();
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render the upgrade block height', () => {
|
||||
const { getByTestId } = renderComponent();
|
||||
expect(getByTestId('protocol-upgrade-block-height')).toHaveTextContent(
|
||||
'12345'
|
||||
);
|
||||
});
|
||||
|
||||
it('should render the state', () => {
|
||||
const { getByTestId } = renderComponent();
|
||||
expect(getByTestId('protocol-upgrade-state')).toHaveTextContent('Pending');
|
||||
});
|
||||
|
||||
it('should render the vega release tag', () => {
|
||||
const { getByTestId } = renderComponent();
|
||||
expect(getByTestId('protocol-upgrade-release-tag')).toHaveTextContent(
|
||||
'v0.1.234'
|
||||
);
|
||||
});
|
||||
});
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
KeyValueTable,
|
||||
KeyValueTableRow,
|
||||
RoundedWrapper,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from '../../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
|
||||
|
||||
export interface ProtocolUpgradeProposalDetailInfoProps {
|
||||
proposal: ProtocolUpgradeProposalFieldsFragment;
|
||||
lastBlockHeight?: string;
|
||||
}
|
||||
|
||||
export const ProtocolUpgradeProposalDetailInfo = ({
|
||||
proposal,
|
||||
lastBlockHeight,
|
||||
}: ProtocolUpgradeProposalDetailInfoProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="mb-10">
|
||||
<SubHeading title={t('proposal')} />
|
||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||
<KeyValueTable data-testid="protocol-upgrade-proposal-details">
|
||||
<KeyValueTableRow>
|
||||
<span className="uppercase">{t('upgradeBlockHeight')}</span>
|
||||
|
||||
<span data-testid="protocol-upgrade-block-height">
|
||||
{proposal.upgradeBlockHeight}{' '}
|
||||
{lastBlockHeight && (
|
||||
<>
|
||||
({t('currently')} {lastBlockHeight})
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
|
||||
<KeyValueTableRow>
|
||||
<span className="uppercase">{t('state')}</span>
|
||||
|
||||
<span data-testid="protocol-upgrade-state">
|
||||
{t(`${proposal.status}`)}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
|
||||
<KeyValueTableRow noBorder={true}>
|
||||
<span className="uppercase">{t('vegaReleaseTag')}</span>
|
||||
|
||||
<span data-testid="protocol-upgrade-release-tag">
|
||||
{proposal.vegaReleaseTag}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
</KeyValueTable>
|
||||
</RoundedWrapper>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { ProtocolUpgradeProposalsListItem } from './protocol-upgrade-proposals-list-item';
|
||||
import { ProtocolUpgradeProposalStatus } from '@vegaprotocol/types';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from '../../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
|
||||
|
||||
const proposal = {
|
||||
status:
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING,
|
||||
vegaReleaseTag: 'v1.0.0',
|
||||
upgradeBlockHeight: '12345',
|
||||
} as ProtocolUpgradeProposalFieldsFragment;
|
||||
|
||||
const renderComponent = (proposal: ProtocolUpgradeProposalFieldsFragment) =>
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<ProtocolUpgradeProposalsListItem proposal={proposal} />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
describe('ProtocolUpgradeProposalsListItem', () => {
|
||||
it('renders the correct status icon for each proposal status', () => {
|
||||
const statuses = [
|
||||
{
|
||||
status:
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED,
|
||||
icon: 'protocol-upgrade-proposal-status-icon-rejected',
|
||||
},
|
||||
{
|
||||
status:
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING,
|
||||
icon: 'protocol-upgrade-proposal-status-icon-pending',
|
||||
},
|
||||
{
|
||||
status:
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED,
|
||||
icon: 'protocol-upgrade-proposal-status-icon-approved',
|
||||
},
|
||||
{
|
||||
status:
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_UNSPECIFIED,
|
||||
icon: 'protocol-upgrade-proposal-status-icon-unspecified',
|
||||
},
|
||||
];
|
||||
|
||||
statuses.forEach(({ status, icon }) => {
|
||||
renderComponent({ ...proposal, status });
|
||||
const statusIcon = screen.getByTestId(icon);
|
||||
expect(statusIcon).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the correct Vega release tag', () => {
|
||||
renderComponent(proposal);
|
||||
const releaseTag = screen.getByTestId(
|
||||
'protocol-upgrade-proposal-release-tag'
|
||||
);
|
||||
expect(releaseTag).toHaveTextContent(proposal.vegaReleaseTag);
|
||||
});
|
||||
|
||||
it('renders the correct upgrade block height', () => {
|
||||
renderComponent(proposal);
|
||||
const blockHeight = screen.getByTestId(
|
||||
'protocol-upgrade-proposal-block-height'
|
||||
);
|
||||
expect(blockHeight).toHaveTextContent(proposal.upgradeBlockHeight);
|
||||
});
|
||||
});
|
||||
-124
@@ -1,124 +0,0 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {
|
||||
Button,
|
||||
Icon,
|
||||
Intent,
|
||||
Lozenge,
|
||||
RoundedWrapper,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { stripFullStops } from '@vegaprotocol/utils';
|
||||
import { ProtocolUpgradeProposalStatus } from '@vegaprotocol/types';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from '../../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
|
||||
import Routes from '../../../routes';
|
||||
|
||||
interface ProtocolProposalsListItemProps {
|
||||
proposal: ProtocolUpgradeProposalFieldsFragment;
|
||||
}
|
||||
|
||||
export const ProtocolUpgradeProposalsListItem = ({
|
||||
proposal,
|
||||
}: ProtocolProposalsListItemProps) => {
|
||||
const { t } = useTranslation();
|
||||
if (!proposal || !proposal.upgradeBlockHeight) return null;
|
||||
|
||||
let proposalStatusIcon: ReactNode;
|
||||
|
||||
switch (proposal.status) {
|
||||
case ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED:
|
||||
proposalStatusIcon = (
|
||||
<div data-testid="protocol-upgrade-proposal-status-icon-rejected">
|
||||
<Icon name={'cross'} />
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
case ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING:
|
||||
proposalStatusIcon = (
|
||||
<div data-testid="protocol-upgrade-proposal-status-icon-pending">
|
||||
<Icon name={'time'} />
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
case ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED:
|
||||
proposalStatusIcon = (
|
||||
<div data-testid="protocol-upgrade-proposal-status-icon-approved">
|
||||
<Icon name={'tick'} />
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
case ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_UNSPECIFIED:
|
||||
proposalStatusIcon = (
|
||||
<div data-testid="protocol-upgrade-proposal-status-icon-unspecified">
|
||||
<Icon name={'disable'} />
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<li
|
||||
id={proposal.upgradeBlockHeight}
|
||||
data-testid="protocol-upgrade-proposals-list-item"
|
||||
>
|
||||
<RoundedWrapper paddingBottom={true} heightFull={true}>
|
||||
<div
|
||||
data-testid="protocol-upgrade-proposal-title"
|
||||
className="text-sm mb-2"
|
||||
>
|
||||
<SubHeading title={`Vega release ${proposal.vegaReleaseTag}`} />
|
||||
</div>
|
||||
|
||||
<div className="text-sm">
|
||||
<div
|
||||
data-testid="protocol-upgrade-proposal-type"
|
||||
className="flex items-center gap-2 mb-4"
|
||||
>
|
||||
<Lozenge variant={Intent.Success}>{t('networkUpgrade')}</Lozenge>
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-testid="protocol-upgrade-proposal-release-tag"
|
||||
className="mb-2"
|
||||
>
|
||||
<span className="pr-2">{t('vegaReleaseTag')}</span>
|
||||
<Lozenge>{proposal.vegaReleaseTag}</Lozenge>
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-testid="protocol-upgrade-proposal-block-height"
|
||||
className="mb-2"
|
||||
>
|
||||
<span className="pr-2">{t('upgradeBlockHeight')}</span>
|
||||
<Lozenge>{proposal.upgradeBlockHeight}</Lozenge>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-[1fr_auto] mt-3 items-start gap-2">
|
||||
<div className="col-start-1 row-start-1 text-white">
|
||||
<div
|
||||
data-testid="protocol-upgrade-proposal-status"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<span>{t(`${proposal.status}`)}</span>
|
||||
<span>{proposalStatusIcon}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-start-2 row-start-2 justify-self-end">
|
||||
<Link
|
||||
to={`${Routes.PROPOSALS}/protocol-upgrade/${stripFullStops(
|
||||
proposal.vegaReleaseTag
|
||||
)}`}
|
||||
>
|
||||
<Button data-testid="view-proposal-btn" size="sm">
|
||||
{t('View')}
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RoundedWrapper>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
@@ -5,18 +5,13 @@ import { useTranslation } from 'react-i18next';
|
||||
import { SplashLoader } from '../../../components/splash-loader';
|
||||
import { ProposalsList } from '../components/proposals-list';
|
||||
import { useProposalsQuery } from './__generated__/Proposals';
|
||||
import type { ProposalFieldsFragment } from './__generated__/Proposals';
|
||||
import type { NodeConnection, NodeEdge } from '@vegaprotocol/utils';
|
||||
import { getNodes } from '@vegaprotocol/utils';
|
||||
import flow from 'lodash/flow';
|
||||
import {
|
||||
ProposalState,
|
||||
ProtocolUpgradeProposalStatus,
|
||||
} from '@vegaprotocol/types';
|
||||
import type { NodeConnection, NodeEdge } from '@vegaprotocol/utils';
|
||||
import type { ProposalFieldsFragment } from './__generated__/Proposals';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from '../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import { useProtocolUpgradesQuery } from '../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
|
||||
|
||||
const orderByDate = (arr: ProposalFieldsFragment[]) =>
|
||||
orderBy(
|
||||
@@ -25,15 +20,6 @@ const orderByDate = (arr: ProposalFieldsFragment[]) =>
|
||||
['desc', 'desc']
|
||||
);
|
||||
|
||||
const orderByUpgradeBlockHeight = (
|
||||
arr: ProtocolUpgradeProposalFieldsFragment[]
|
||||
) =>
|
||||
orderBy(
|
||||
arr,
|
||||
[(p) => p?.upgradeBlockHeight, (p) => p.vegaReleaseTag],
|
||||
['desc', 'desc']
|
||||
);
|
||||
|
||||
export function getNotRejectedProposals<T extends ProposalFieldsFragment>(
|
||||
data?: NodeConnection<NodeEdge<T>> | null
|
||||
): T[] {
|
||||
@@ -46,21 +32,6 @@ export function getNotRejectedProposals<T extends ProposalFieldsFragment>(
|
||||
])(data);
|
||||
}
|
||||
|
||||
export function getNotRejectedProtocolUpgradeProposals<
|
||||
T extends ProtocolUpgradeProposalFieldsFragment
|
||||
>(data?: NodeConnection<NodeEdge<T>> | null): T[] {
|
||||
return flow([
|
||||
(data) =>
|
||||
getNodes<ProtocolUpgradeProposalFieldsFragment>(data, (p) =>
|
||||
p
|
||||
? p.status !==
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED
|
||||
: false
|
||||
),
|
||||
orderByUpgradeBlockHeight,
|
||||
])(data);
|
||||
}
|
||||
|
||||
export const ProposalsContainer = () => {
|
||||
const { t } = useTranslation();
|
||||
const { data, loading, error } = useProposalsQuery({
|
||||
@@ -69,16 +40,6 @@ export const ProposalsContainer = () => {
|
||||
errorPolicy: 'ignore',
|
||||
});
|
||||
|
||||
const {
|
||||
data: protocolUpgradesData,
|
||||
loading: protocolUpgradesLoading,
|
||||
error: protocolUpgradesError,
|
||||
} = useProtocolUpgradesQuery({
|
||||
pollInterval: 5000,
|
||||
fetchPolicy: 'network-only',
|
||||
errorPolicy: 'ignore',
|
||||
});
|
||||
|
||||
const proposals = useMemo(
|
||||
() =>
|
||||
getNotRejectedProposals<ProposalFieldsFragment>(
|
||||
@@ -87,25 +48,15 @@ export const ProposalsContainer = () => {
|
||||
[data]
|
||||
);
|
||||
|
||||
const protocolUpgradeProposals = useMemo(
|
||||
() =>
|
||||
protocolUpgradesData
|
||||
? getNotRejectedProtocolUpgradeProposals<ProtocolUpgradeProposalFieldsFragment>(
|
||||
protocolUpgradesData.protocolUpgradeProposals
|
||||
)
|
||||
: [],
|
||||
[protocolUpgradesData]
|
||||
);
|
||||
|
||||
if (error || protocolUpgradesError) {
|
||||
if (error) {
|
||||
return (
|
||||
<Callout intent={Intent.Danger} title={t('Something went wrong')}>
|
||||
<pre>{error?.message || protocolUpgradesError?.message}</pre>
|
||||
<pre>{error.message}</pre>
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
||||
if (loading || protocolUpgradesLoading) {
|
||||
if (loading) {
|
||||
return (
|
||||
<Splash>
|
||||
<SplashLoader />
|
||||
@@ -113,11 +64,5 @@ export const ProposalsContainer = () => {
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ProposalsList
|
||||
proposals={proposals}
|
||||
protocolUpgradeProposals={protocolUpgradeProposals}
|
||||
lastBlockHeight={protocolUpgradesData?.lastBlockHeight}
|
||||
/>
|
||||
);
|
||||
return <ProposalsList proposals={proposals} />;
|
||||
};
|
||||
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
fragment ProtocolUpgradeProposalFields on ProtocolUpgradeProposal {
|
||||
upgradeBlockHeight
|
||||
vegaReleaseTag
|
||||
approvers
|
||||
status
|
||||
}
|
||||
|
||||
query ProtocolUpgrades {
|
||||
lastBlockHeight
|
||||
protocolUpgradeProposals {
|
||||
edges {
|
||||
node {
|
||||
...ProtocolUpgradeProposalFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
-59
@@ -1,59 +0,0 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type ProtocolUpgradeProposalFieldsFragment = { __typename?: 'ProtocolUpgradeProposal', upgradeBlockHeight: string, vegaReleaseTag: string, approvers: Array<string>, status: Types.ProtocolUpgradeProposalStatus };
|
||||
|
||||
export type ProtocolUpgradesQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type ProtocolUpgradesQuery = { __typename?: 'Query', lastBlockHeight: string, protocolUpgradeProposals?: { __typename?: 'ProtocolUpgradeProposalConnection', edges?: Array<{ __typename?: 'ProtocolUpgradeProposalEdge', node: { __typename?: 'ProtocolUpgradeProposal', upgradeBlockHeight: string, vegaReleaseTag: string, approvers: Array<string>, status: Types.ProtocolUpgradeProposalStatus } }> | null } | null };
|
||||
|
||||
export const ProtocolUpgradeProposalFieldsFragmentDoc = gql`
|
||||
fragment ProtocolUpgradeProposalFields on ProtocolUpgradeProposal {
|
||||
upgradeBlockHeight
|
||||
vegaReleaseTag
|
||||
approvers
|
||||
status
|
||||
}
|
||||
`;
|
||||
export const ProtocolUpgradesDocument = gql`
|
||||
query ProtocolUpgrades {
|
||||
lastBlockHeight
|
||||
protocolUpgradeProposals {
|
||||
edges {
|
||||
node {
|
||||
...ProtocolUpgradeProposalFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${ProtocolUpgradeProposalFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useProtocolUpgradesQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useProtocolUpgradesQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useProtocolUpgradesQuery` 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 } = useProtocolUpgradesQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useProtocolUpgradesQuery(baseOptions?: Apollo.QueryHookOptions<ProtocolUpgradesQuery, ProtocolUpgradesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<ProtocolUpgradesQuery, ProtocolUpgradesQueryVariables>(ProtocolUpgradesDocument, options);
|
||||
}
|
||||
export function useProtocolUpgradesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ProtocolUpgradesQuery, ProtocolUpgradesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<ProtocolUpgradesQuery, ProtocolUpgradesQueryVariables>(ProtocolUpgradesDocument, options);
|
||||
}
|
||||
export type ProtocolUpgradesQueryHookResult = ReturnType<typeof useProtocolUpgradesQuery>;
|
||||
export type ProtocolUpgradesLazyQueryHookResult = ReturnType<typeof useProtocolUpgradesLazyQuery>;
|
||||
export type ProtocolUpgradesQueryResult = Apollo.QueryResult<ProtocolUpgradesQuery, ProtocolUpgradesQueryVariables>;
|
||||
@@ -1 +0,0 @@
|
||||
export { ProtocolUpgradeProposalContainer as default } from './protocol-upgrade-proposal-container';
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { removePaginationWrapper, stripFullStops } from '@vegaprotocol/utils';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
import { ProtocolUpgradeProposal } from './protocol-upgrade-proposal';
|
||||
import { ProposalNotFound } from '../components/proposal-not-found';
|
||||
import { useProtocolUpgradesQuery } from './__generated__/ProtocolUpgradeProposals';
|
||||
import { useNodesQuery } from '../../staking/home/__generated__/Nodes';
|
||||
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
|
||||
|
||||
export const ProtocolUpgradeProposalContainer = () => {
|
||||
const params = useParams<{ proposalReleaseTag: string }>();
|
||||
|
||||
const { data, loading, error, refetch } = useProtocolUpgradesQuery({
|
||||
fetchPolicy: 'network-only',
|
||||
errorPolicy: 'ignore',
|
||||
skip: !params.proposalReleaseTag,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(refetch, 1000);
|
||||
return () => clearInterval(interval);
|
||||
}, [refetch]);
|
||||
|
||||
const {
|
||||
data: nodesData,
|
||||
error: nodesError,
|
||||
loading: nodesLoading,
|
||||
refetch: nodesRefetch,
|
||||
} = useNodesQuery();
|
||||
|
||||
useRefreshAfterEpoch(nodesData?.epoch.timestamps.expiry, nodesRefetch);
|
||||
|
||||
const protocolUpgradeProposal = useMemo(() => {
|
||||
if (!data?.protocolUpgradeProposals) return null;
|
||||
|
||||
const proposals = removePaginationWrapper(
|
||||
data.protocolUpgradeProposals.edges
|
||||
);
|
||||
|
||||
return proposals.find(
|
||||
({ vegaReleaseTag }) =>
|
||||
params.proposalReleaseTag &&
|
||||
params.proposalReleaseTag === stripFullStops(vegaReleaseTag)
|
||||
);
|
||||
}, [data, params.proposalReleaseTag]);
|
||||
|
||||
const consensusValidators = useMemo(() => {
|
||||
if (!nodesData?.nodesConnection.edges) return null;
|
||||
|
||||
const nodes = removePaginationWrapper(nodesData.nodesConnection.edges);
|
||||
|
||||
return nodes.filter(
|
||||
({ rankingScore: { status } }) =>
|
||||
status === Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT
|
||||
);
|
||||
}, [nodesData]);
|
||||
|
||||
return (
|
||||
<AsyncRenderer
|
||||
loading={loading || nodesLoading}
|
||||
error={error || nodesError}
|
||||
data={{ ...data, ...nodesData }}
|
||||
>
|
||||
{protocolUpgradeProposal ? (
|
||||
<ProtocolUpgradeProposal
|
||||
proposal={protocolUpgradeProposal}
|
||||
lastBlockHeight={data?.lastBlockHeight}
|
||||
consensusValidators={consensusValidators}
|
||||
/>
|
||||
) : (
|
||||
<ProposalNotFound />
|
||||
)}
|
||||
</AsyncRenderer>
|
||||
);
|
||||
};
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
ProtocolUpgradeProposal,
|
||||
getConsensusApprovals,
|
||||
getConsensusApprovalsVotingPower,
|
||||
getConsensusApprovalsVotingPowerPercentage,
|
||||
} from './protocol-upgrade-proposal';
|
||||
import { ProtocolUpgradeProposalStatus } from '@vegaprotocol/types';
|
||||
import { getNormalisedVotingPower } from '../../staking/shared';
|
||||
import type { NodesFragmentFragment } from '../../staking/home/__generated__/Nodes';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from './__generated__/ProtocolUpgradeProposals';
|
||||
|
||||
const mockProposal: ProtocolUpgradeProposalFieldsFragment = {
|
||||
vegaReleaseTag: 'v0.1.234',
|
||||
status:
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING,
|
||||
upgradeBlockHeight: '12345',
|
||||
approvers: [],
|
||||
};
|
||||
|
||||
const mockConsensusValidators: NodesFragmentFragment[] = [
|
||||
{
|
||||
id: 'ccc022b7e63a4d0a6d3a193c3940c88574060e58a184964c994998d86835a1b4',
|
||||
name: 'Marvin',
|
||||
avatarUrl: 'https://upload.wikimedia.org/wikipedia/en/2/25/Marvin-TV-3.jpg',
|
||||
pubkey: '6abc23391a9f888ab240415bf63d6844b03fc360be822f4a1d2cd832d87b2917',
|
||||
stakedTotal: '14182454495731682635157',
|
||||
stakedByOperator: '1000000000000000000000',
|
||||
stakedByDelegates: '13182454495731682635157',
|
||||
pendingStake: '0',
|
||||
rankingScore: {
|
||||
rankingScore: '0.67845061012234727427532760837568',
|
||||
stakeScore: '0.3392701644525644',
|
||||
performanceScore: '0.9998677767864936',
|
||||
votingPower: '3500',
|
||||
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
__typename: 'RankingScore',
|
||||
},
|
||||
__typename: 'Node',
|
||||
},
|
||||
{
|
||||
id: 'ccc022b7e63a4d0a6d3a193c3940c88574060e58a184964c994998d86835a1b5',
|
||||
name: 'Barvin',
|
||||
avatarUrl: 'https://upload.wikimedia.org/wikipedia/en/2/25/Barvin-TV-3.jpg',
|
||||
pubkey: '6abc23391a9f888ab240415bf63d6844b03fc360be822f4a1d2cd832d87b291b',
|
||||
stakedTotal: '1418245449573168263',
|
||||
stakedByOperator: '100000000000000000',
|
||||
stakedByDelegates: '1318245449573168263',
|
||||
pendingStake: '0',
|
||||
rankingScore: {
|
||||
rankingScore: '0.5',
|
||||
stakeScore: '0.3',
|
||||
performanceScore: '0.98',
|
||||
votingPower: '2500',
|
||||
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
__typename: 'RankingScore',
|
||||
},
|
||||
__typename: 'Node',
|
||||
},
|
||||
];
|
||||
|
||||
const renderComponent = () =>
|
||||
render(
|
||||
<ProtocolUpgradeProposal proposal={mockProposal} consensusValidators={[]} />
|
||||
);
|
||||
|
||||
describe('ProtocolUpgradeProposal', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = renderComponent();
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getConsensusApprovals', () => {
|
||||
it('returns an empty array when there are no matching approvers', () => {
|
||||
const result = getConsensusApprovals(mockConsensusValidators, {
|
||||
...mockProposal,
|
||||
approvers: [],
|
||||
});
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns the correct consensus approvals when there are matching approvers', () => {
|
||||
const expectedApprovals = mockConsensusValidators[1];
|
||||
|
||||
const result = getConsensusApprovals(mockConsensusValidators, {
|
||||
...mockProposal,
|
||||
approvers: [
|
||||
'6abc23391a9f888ab240415bf63d6844b03fc360be822f4a1d2cd832d87b291b',
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0].id).toEqual(expectedApprovals.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getConsensusApprovalsVotingPower', () => {
|
||||
it('returns 0 when the input array is empty', () => {
|
||||
const result = getConsensusApprovalsVotingPower([]);
|
||||
expect(result).toBe(0);
|
||||
});
|
||||
|
||||
it('returns the correct sum of voting power for a given array of consensus validators', () => {
|
||||
const expectedSum = mockConsensusValidators.reduce(
|
||||
(acc, curr) => acc + Number(curr.rankingScore.votingPower),
|
||||
0
|
||||
);
|
||||
|
||||
const result = getConsensusApprovalsVotingPower(mockConsensusValidators);
|
||||
expect(result).toBe(expectedSum);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getConsensusApprovalsVotingPowerPercentage', () => {
|
||||
it('returns "0%" when the input value is 0 or less', () => {
|
||||
const resultZero = getConsensusApprovalsVotingPowerPercentage(0);
|
||||
const resultNegative = getConsensusApprovalsVotingPowerPercentage(-10);
|
||||
expect(resultZero).toBe('0%');
|
||||
expect(resultNegative).toBe('0%');
|
||||
});
|
||||
|
||||
it('returns the correct percentage string when the input value is greater than 0', () => {
|
||||
const inputValue = 12345;
|
||||
const expectedPercentage = getNormalisedVotingPower(
|
||||
inputValue.toString(),
|
||||
2
|
||||
);
|
||||
|
||||
const result = getConsensusApprovalsVotingPowerPercentage(inputValue);
|
||||
expect(result).toBe(expectedPercentage);
|
||||
});
|
||||
});
|
||||
@@ -1,83 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import { ProtocolUpgradeProposalDetailHeader } from '../components/protocol-upgrade-proposal-detail-header';
|
||||
import { ProtocolUpdateProposalDetailApprovals } from '../components/protocol-upgrade-proposal-detail-approvals';
|
||||
import { ProtocolUpgradeProposalDetailInfo } from '../components/protocol-upgrade-proposal-detail-info';
|
||||
import { getNormalisedVotingPower } from '../../staking/shared';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from './__generated__/ProtocolUpgradeProposals';
|
||||
import type { NodesFragmentFragment } from '../../staking/home/__generated__/Nodes';
|
||||
|
||||
export interface ProtocolUpgradeProposalProps {
|
||||
proposal: ProtocolUpgradeProposalFieldsFragment;
|
||||
consensusValidators: NodesFragmentFragment[] | null;
|
||||
lastBlockHeight?: string;
|
||||
}
|
||||
|
||||
export const getConsensusApprovals = (
|
||||
consensusValidators: NodesFragmentFragment[],
|
||||
proposal: ProtocolUpgradeProposalFieldsFragment
|
||||
) =>
|
||||
consensusValidators?.filter(({ pubkey }) =>
|
||||
proposal.approvers?.includes(pubkey)
|
||||
);
|
||||
|
||||
export const getConsensusApprovalsVotingPower = (
|
||||
consensusValidators: NodesFragmentFragment[]
|
||||
) =>
|
||||
consensusValidators?.reduce<number>(
|
||||
(acc: number, curr: NodesFragmentFragment) => {
|
||||
return acc + Number(curr.rankingScore.votingPower);
|
||||
},
|
||||
0
|
||||
);
|
||||
|
||||
export const getConsensusApprovalsVotingPowerPercentage = (
|
||||
consensusApprovalsVotingPower: number
|
||||
) =>
|
||||
consensusApprovalsVotingPower > 0
|
||||
? getNormalisedVotingPower(consensusApprovalsVotingPower.toString(), 2)
|
||||
: '0%';
|
||||
|
||||
export const ProtocolUpgradeProposal = ({
|
||||
proposal,
|
||||
lastBlockHeight,
|
||||
consensusValidators,
|
||||
}: ProtocolUpgradeProposalProps) => {
|
||||
const consensusApprovals = useMemo(
|
||||
() => getConsensusApprovals(consensusValidators || [], proposal),
|
||||
[consensusValidators, proposal]
|
||||
);
|
||||
|
||||
const consensusApprovalsVotingPower = useMemo(
|
||||
() => getConsensusApprovalsVotingPower(consensusApprovals || []),
|
||||
[consensusApprovals]
|
||||
);
|
||||
|
||||
const consensusApprovalsVotingPowerPercentage = useMemo(
|
||||
() =>
|
||||
getConsensusApprovalsVotingPowerPercentage(consensusApprovalsVotingPower),
|
||||
[consensusApprovalsVotingPower]
|
||||
);
|
||||
|
||||
return (
|
||||
<section data-testid="protocol-upgrade-proposal">
|
||||
<ProtocolUpgradeProposalDetailHeader
|
||||
releaseTag={proposal.vegaReleaseTag}
|
||||
/>
|
||||
|
||||
<ProtocolUpgradeProposalDetailInfo
|
||||
proposal={proposal}
|
||||
lastBlockHeight={lastBlockHeight}
|
||||
/>
|
||||
|
||||
{consensusValidators && consensusApprovals && (
|
||||
<ProtocolUpdateProposalDetailApprovals
|
||||
consensusApprovals={consensusApprovals}
|
||||
consensusApprovalsVotingPowerPercentage={
|
||||
consensusApprovalsVotingPowerPercentage
|
||||
}
|
||||
totalConsensusValidators={consensusValidators.length}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -109,13 +109,6 @@ const LazyProposal = React.lazy(
|
||||
)
|
||||
);
|
||||
|
||||
const LazyProtocolUpgradeProposal = React.lazy(
|
||||
() =>
|
||||
import(
|
||||
/* webpackChunkName: "route-governance-protocol-upgrade-proposal", webpackPrefetch: true */ './proposals/protocol-upgrade'
|
||||
)
|
||||
);
|
||||
|
||||
const LazyProposalsList = React.lazy(
|
||||
() =>
|
||||
import(
|
||||
@@ -264,10 +257,6 @@ const routerConfig = [
|
||||
},
|
||||
{ path: 'proposals', element: <LazyProposalsList /> },
|
||||
{ path: ':proposalId', element: <LazyProposal /> },
|
||||
{
|
||||
path: 'protocol-upgrade/:proposalReleaseTag',
|
||||
element: <LazyProtocolUpgradeProposal />,
|
||||
},
|
||||
{ path: 'rejected', element: <LazyRejectedProposalsList /> },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -20,8 +20,8 @@ export const getLastEpochScoreAndPerformance = (
|
||||
};
|
||||
};
|
||||
|
||||
export const getNormalisedVotingPower = (votingPower: string, decimals = 2) =>
|
||||
formatNumberPercentage(new BigNumber(votingPower).dividedBy(100), decimals);
|
||||
export const getNormalisedVotingPower = (votingPower: string) =>
|
||||
formatNumberPercentage(new BigNumber(votingPower).dividedBy(100), 2);
|
||||
|
||||
export const getUnnormalisedVotingPower = (
|
||||
validatorScore: string | null | undefined
|
||||
|
||||
@@ -666,7 +666,7 @@
|
||||
"tranche_end": "2023-05-06T00:00:00.000Z",
|
||||
"total_added": "8865",
|
||||
"total_removed": "362.31015740205",
|
||||
"locked_amount": "4874.1459548611110345",
|
||||
"locked_amount": "4947.631059027778128",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "33",
|
||||
@@ -4407,7 +4407,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "86666.297",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "54491.6293588377368963476",
|
||||
"locked_amount": "54550.6765448265232514477",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "86666.297",
|
||||
@@ -4473,7 +4473,7 @@
|
||||
"tranche_end": "2023-06-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "583.71664504477005",
|
||||
"locked_amount": "587.132586741961625",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
@@ -4594,7 +4594,7 @@
|
||||
"tranche_end": "2023-09-01T00:00:00.000Z",
|
||||
"total_added": "17500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "12791.60329232085475",
|
||||
"locked_amount": "12815.2549755938015",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "12500",
|
||||
@@ -4861,7 +4861,7 @@
|
||||
"tranche_end": "2023-08-01T00:00:00.000Z",
|
||||
"total_added": "37500",
|
||||
"total_removed": "12294.731717775",
|
||||
"locked_amount": "21442.24553023327125",
|
||||
"locked_amount": "21493.76774478207375",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -5225,7 +5225,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "129999.45",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "54441.912603447519962385",
|
||||
"locked_amount": "54500.905916308673138415",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129999.45",
|
||||
@@ -5258,7 +5258,7 @@
|
||||
"tranche_end": "2024-04-01T00:00:00.000Z",
|
||||
"total_added": "54144.7663",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "51407.13764596631692808494",
|
||||
"locked_amount": "51443.92658193328217573951",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "54144.7663",
|
||||
@@ -5291,7 +5291,7 @@
|
||||
"tranche_end": "2023-09-03T00:00:00.000Z",
|
||||
"total_added": "62600",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "23409.75395104008482",
|
||||
"locked_amount": "23452.40436960933488",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10000",
|
||||
@@ -5484,7 +5484,7 @@
|
||||
"tranche_end": "2023-09-17T00:00:00.000Z",
|
||||
"total_added": "5000",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "2061.56947615423635",
|
||||
"locked_amount": "2064.976059107052",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "5000",
|
||||
@@ -6025,7 +6025,7 @@
|
||||
"tranche_end": "2023-05-01T00:00:00.000Z",
|
||||
"total_added": "22500",
|
||||
"total_removed": "6871.43713545",
|
||||
"locked_amount": "1428.88322974217355",
|
||||
"locked_amount": "1459.796558471453925",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -6509,7 +6509,7 @@
|
||||
"tranche_end": "2023-06-02T00:00:00.000Z",
|
||||
"total_added": "1939928.38",
|
||||
"total_removed": "928642.9598472029154",
|
||||
"locked_amount": "231168.093511598737240552",
|
||||
"locked_amount": "232489.7989013972454998708",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1852091.69",
|
||||
@@ -40325,7 +40325,7 @@
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "3732368.4671",
|
||||
"total_removed": "715655.108029600523393",
|
||||
"locked_amount": "379726.105748070797206746073",
|
||||
"locked_amount": "381757.201289964680148718477",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1998.95815",
|
||||
@@ -41718,7 +41718,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "15870102.715470999700000001",
|
||||
"total_removed": "835090.78677275839915352",
|
||||
"locked_amount": "6646171.9758772447834505578413098637685861",
|
||||
"locked_amount": "6653374.1102600029976151216559241015233847",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "16249.93",
|
||||
@@ -48163,8 +48163,8 @@
|
||||
"tranche_start": "2021-11-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-05T00:00:00.000Z",
|
||||
"total_added": "14597706.0446472999",
|
||||
"total_removed": "5845111.643096907348272126",
|
||||
"locked_amount": "414258.305630822730645455902270797",
|
||||
"total_removed": "5844740.479416869886902626",
|
||||
"locked_amount": "420907.270106923449603004591821117",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129284.449",
|
||||
@@ -48443,11 +48443,6 @@
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x5cee329248d32efdbd9e7f2b223f1714843a154b530cafd9f5df43a1d45c625b"
|
||||
},
|
||||
{
|
||||
"amount": "371.1636800374613695",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xc4a521e74b6b9c9c01e7fbd950f4096d3e6473a773818b4fdf0c9d974ee5fc7e"
|
||||
},
|
||||
{
|
||||
"amount": "37462.74710421168752574",
|
||||
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
|
||||
@@ -51729,12 +51724,6 @@
|
||||
"tranche_id": 3,
|
||||
"tx": "0x5cee329248d32efdbd9e7f2b223f1714843a154b530cafd9f5df43a1d45c625b"
|
||||
},
|
||||
{
|
||||
"amount": "371.1636800374613695",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xc4a521e74b6b9c9c01e7fbd950f4096d3e6473a773818b4fdf0c9d974ee5fc7e"
|
||||
},
|
||||
{
|
||||
"amount": "1383.345213676043696",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@@ -54473,8 +54462,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "359123.469575",
|
||||
"withdrawn_tokens": "348774.8193074565797845",
|
||||
"remaining_tokens": "10348.6502675434202155"
|
||||
"withdrawn_tokens": "348403.655627419118415",
|
||||
"remaining_tokens": "10719.813947580881585"
|
||||
},
|
||||
{
|
||||
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
|
||||
@@ -58109,7 +58098,7 @@
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "472355.6199999996",
|
||||
"total_removed": "43120.0853616251849",
|
||||
"locked_amount": "60169.7720627409513147623313039",
|
||||
"locked_amount": "60491.61076159115414066601116184",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "3000",
|
||||
|
||||
@@ -11,7 +11,7 @@ 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/test/announcements.json
|
||||
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"
|
||||
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
|
||||
@@ -1,5 +1,3 @@
|
||||
export * from './use-environment';
|
||||
export * from './use-links';
|
||||
export * from './use-node-health';
|
||||
export * from './use-vega-releases';
|
||||
export * from './use-vega-release';
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,41 +0,0 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import fetchMock from 'fetch-mock';
|
||||
import {
|
||||
GITHUB_VEGA_DEV_RELEASES,
|
||||
GITHUB_VEGA_RELEASES,
|
||||
} from './use-vega-releases';
|
||||
import {
|
||||
GITHUB_VEGA_RELEASES_DATA,
|
||||
GITHUB_VEGA_DEV_RELEASES_DATA,
|
||||
} from './mocks/github-releases';
|
||||
import { useVegaRelease } from './use-vega-release';
|
||||
|
||||
describe('useVegaRelease', () => {
|
||||
beforeEach(() => {
|
||||
fetchMock.get(GITHUB_VEGA_RELEASES, GITHUB_VEGA_RELEASES_DATA);
|
||||
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, GITHUB_VEGA_DEV_RELEASES_DATA);
|
||||
});
|
||||
afterEach(() => {
|
||||
fetchMock.reset();
|
||||
});
|
||||
|
||||
it('should return release information by given tag', async () => {
|
||||
const { result } = renderHook(() => useVegaRelease('v0.70.1'));
|
||||
await waitFor(() => {
|
||||
expect(result.current).toBeTruthy();
|
||||
expect(result.current?.tagName).toEqual('v0.70.1');
|
||||
expect(result.current?.htmlUrl).toEqual(
|
||||
'https://github.com/vegaprotocol/vega/releases/tag/v0.70.1'
|
||||
);
|
||||
expect(result.current?.name).toEqual('v0.70.1');
|
||||
expect(result.current?.isDraft).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined when a release cannot be found', async () => {
|
||||
const { result } = renderHook(() => useVegaRelease('v0.70.1'));
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,9 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useVegaReleases } from './use-vega-releases';
|
||||
|
||||
export const useVegaRelease = (tag: string, includeDevReleases = false) => {
|
||||
const { data } = useVegaReleases();
|
||||
return useMemo(() => {
|
||||
return data?.find((r) => r.tagName === tag);
|
||||
}, [data, tag]);
|
||||
};
|
||||
@@ -1,58 +0,0 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import fetchMock from 'fetch-mock';
|
||||
import {
|
||||
GITHUB_VEGA_DEV_RELEASES,
|
||||
GITHUB_VEGA_RELEASES,
|
||||
useVegaReleases,
|
||||
} from './use-vega-releases';
|
||||
import {
|
||||
GITHUB_VEGA_RELEASES_DATA,
|
||||
GITHUB_VEGA_DEV_RELEASES_DATA,
|
||||
} from './mocks/github-releases';
|
||||
|
||||
describe('useVegaReleases', () => {
|
||||
afterEach(() => {
|
||||
fetchMock.reset();
|
||||
});
|
||||
|
||||
it('should return an empty list when request is unsuccessful', async () => {
|
||||
fetchMock.get(GITHUB_VEGA_RELEASES, 404);
|
||||
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, 404);
|
||||
|
||||
const { result } = renderHook(() => useVegaReleases());
|
||||
expect(result.current.loading).toBeTruthy();
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBeFalsy();
|
||||
expect(result.current.data).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a list of releases', async () => {
|
||||
fetchMock.get(GITHUB_VEGA_RELEASES, GITHUB_VEGA_RELEASES_DATA);
|
||||
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, GITHUB_VEGA_DEV_RELEASES_DATA);
|
||||
|
||||
const { result } = renderHook(() => useVegaReleases());
|
||||
expect(result.current.loading).toBeTruthy();
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBeFalsy();
|
||||
expect(result.current).not.toEqual([]);
|
||||
const data = result.current.data;
|
||||
expect(data?.[0].tagName).toEqual('v0.70.3');
|
||||
expect(data?.[0].htmlUrl).toEqual(
|
||||
'https://github.com/vegaprotocol/vega/releases/tag/v0.70.3'
|
||||
);
|
||||
expect(data?.[1].tagName).toEqual('v0.70.2');
|
||||
expect(data?.[2].tagName).toEqual('v0.70.1');
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a list of releases including dev releases', async () => {
|
||||
fetchMock.get(GITHUB_VEGA_RELEASES, GITHUB_VEGA_RELEASES_DATA);
|
||||
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, GITHUB_VEGA_DEV_RELEASES_DATA);
|
||||
const { result } = renderHook(() => useVegaReleases(true));
|
||||
await waitFor(() => {
|
||||
expect(result.current.data?.length).toBeGreaterThan(30);
|
||||
expect(fetchMock.calls().length).toEqual(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,124 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import z from 'zod';
|
||||
|
||||
export const GITHUB_VEGA_RELEASES =
|
||||
'https://api.github.com/repos/vegaprotocol/vega/releases';
|
||||
export const GITHUB_VEGA_DEV_RELEASES =
|
||||
'https://api.github.com/repos/vegaprotocol/vega-dev-releases/releases';
|
||||
|
||||
const GithubReleaseSchema = z.object({
|
||||
url: z.string(),
|
||||
html_url: z.string(),
|
||||
id: z.number(),
|
||||
tag_name: z.string(),
|
||||
name: z.string().nullable(),
|
||||
draft: z.boolean(),
|
||||
created_at: z.string().datetime(),
|
||||
});
|
||||
|
||||
const GithubReleasesSchema = z.array(GithubReleaseSchema);
|
||||
|
||||
type ReleaseInfo = {
|
||||
id: number;
|
||||
name: string;
|
||||
tagName: string;
|
||||
htmlUrl: string;
|
||||
url: string;
|
||||
isDraft: boolean;
|
||||
createdAt: Date;
|
||||
isDevRelease: boolean;
|
||||
};
|
||||
|
||||
const toReleaseInfo = (
|
||||
releaseData: z.infer<typeof GithubReleaseSchema>,
|
||||
isDevRelease: boolean
|
||||
): ReleaseInfo => ({
|
||||
id: releaseData.id,
|
||||
name: releaseData.name || '',
|
||||
tagName: releaseData.tag_name,
|
||||
htmlUrl: releaseData.html_url,
|
||||
url: releaseData.url,
|
||||
isDraft: releaseData.draft,
|
||||
createdAt: new Date(releaseData.created_at),
|
||||
isDevRelease,
|
||||
});
|
||||
|
||||
enum ReleaseFeed {
|
||||
// @ts-ignore TS18033 - allowed in 5.0
|
||||
Vega = GITHUB_VEGA_RELEASES,
|
||||
// @ts-ignore TS18033
|
||||
VegaDev = GITHUB_VEGA_DEV_RELEASES,
|
||||
}
|
||||
|
||||
const fetchReleases = async (feed: ReleaseFeed) => {
|
||||
const response = await fetch(String(feed), {
|
||||
cache: 'force-cache',
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const json = await response.json();
|
||||
const data = GithubReleasesSchema.parse(json);
|
||||
return data.map((d) => toReleaseInfo(d, feed === ReleaseFeed.VegaDev));
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
type State = {
|
||||
loading: boolean;
|
||||
data: ReleaseInfo[] | null;
|
||||
error: Error | null | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves a list of vega releases from github.
|
||||
* First element is the newest.
|
||||
*/
|
||||
export const useVegaReleases = (includeDevReleases = false) => {
|
||||
const [state, setState] = useState<State>({
|
||||
loading: true,
|
||||
data: null,
|
||||
error: null,
|
||||
});
|
||||
|
||||
const fetchData = useCallback(() => {
|
||||
let mounted = true;
|
||||
|
||||
Promise.all(
|
||||
includeDevReleases
|
||||
? [fetchReleases(ReleaseFeed.Vega), fetchReleases(ReleaseFeed.VegaDev)]
|
||||
: [fetchReleases(ReleaseFeed.Vega)]
|
||||
)
|
||||
.then(([vega, vegaDev]) => {
|
||||
if (mounted) {
|
||||
setState({
|
||||
loading: false,
|
||||
data: (vegaDev ? vega.concat(vegaDev) : vega).sort(
|
||||
(a, b) => b.createdAt.valueOf() - a.createdAt.valueOf()
|
||||
),
|
||||
error: null,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (mounted) {
|
||||
setState({
|
||||
loading: false,
|
||||
data: null,
|
||||
error: err,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, [includeDevReleases, setState]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
return state;
|
||||
};
|
||||
@@ -120,6 +120,40 @@ describe('FillsTable', () => {
|
||||
expect(amountCell).toHaveClass('text-vega-pink');
|
||||
});
|
||||
|
||||
it('should format cells correctly for side unspecified', async () => {
|
||||
const partyId = 'party-id';
|
||||
const buyerFill = generateFill({
|
||||
...defaultFill,
|
||||
seller: {
|
||||
id: partyId,
|
||||
},
|
||||
aggressor: Schema.Side.SIDE_UNSPECIFIED,
|
||||
sellerFee: {
|
||||
makerFee: '1',
|
||||
infrastructureFee: '1',
|
||||
liquidityFee: '1',
|
||||
},
|
||||
});
|
||||
render(<FillsTable partyId={partyId} rowData={[buyerFill]} />);
|
||||
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
buyerFill.market?.tradableInstrument.instrument.name || '',
|
||||
'-3.00',
|
||||
'1.00 BTC',
|
||||
'3.00 BTC',
|
||||
'-',
|
||||
'0.03 BTC',
|
||||
getDateTimeFormat().format(new Date(buyerFill.createdAt)),
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
});
|
||||
|
||||
const amountCell = cells.find((c) => c.getAttribute('col-id') === 'size');
|
||||
expect(amountCell).toHaveClass('text-vega-pink');
|
||||
});
|
||||
|
||||
it('should render correct maker or taker role', async () => {
|
||||
const partyId = 'party-id';
|
||||
const takerFill = generateFill({
|
||||
@@ -190,7 +224,7 @@ describe('FillsTable', () => {
|
||||
makerFee: '1000',
|
||||
totalFee: '6000',
|
||||
};
|
||||
expect(getFeesBreakdown('TAKER', fees)).toEqual(expectedBreakdown);
|
||||
expect(getFeesBreakdown('Taker', fees)).toEqual(expectedBreakdown);
|
||||
});
|
||||
|
||||
it('should return correct fees breakdown for a maker', () => {
|
||||
@@ -205,7 +239,7 @@ describe('FillsTable', () => {
|
||||
makerFee: '-1000',
|
||||
totalFee: '4000',
|
||||
};
|
||||
expect(getFeesBreakdown('MAKER', fees)).toEqual(expectedBreakdown);
|
||||
expect(getFeesBreakdown('Maker', fees)).toEqual(expectedBreakdown);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,8 +26,10 @@ import BigNumber from 'bignumber.js';
|
||||
import type { Trade } from './fills-data-provider';
|
||||
import type { FillFieldsFragment } from './__generated__/Fills';
|
||||
|
||||
const TAKER = 'TAKER';
|
||||
const MAKER = 'MAKER';
|
||||
const TAKER = 'Taker';
|
||||
const MAKER = 'Maker';
|
||||
|
||||
export type Role = typeof TAKER | typeof MAKER | '-';
|
||||
|
||||
export type Props = (AgGridReactProps | AgReactUiProps) & {
|
||||
partyId: string;
|
||||
@@ -180,24 +182,10 @@ const formatTotal = ({
|
||||
};
|
||||
|
||||
const formatRole = (partyId: string) => {
|
||||
return ({ value, data }: VegaValueFormatterParams<Trade, 'aggressor'>) => {
|
||||
const taker = t('Taker');
|
||||
const maker = t('Maker');
|
||||
if (data?.buyer.id === partyId) {
|
||||
if (value === Schema.Side.SIDE_BUY) {
|
||||
return taker;
|
||||
} else {
|
||||
return maker;
|
||||
}
|
||||
} else if (data?.seller.id === partyId) {
|
||||
if (value === Schema.Side.SIDE_SELL) {
|
||||
return taker;
|
||||
} else {
|
||||
return maker;
|
||||
}
|
||||
} else {
|
||||
return '-';
|
||||
}
|
||||
return ({ data }: VegaValueFormatterParams<Trade, 'aggressor'>) => {
|
||||
if (!data) return '-';
|
||||
const { role } = getRoleAndFees({ data, partyId });
|
||||
return role;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -222,6 +210,15 @@ const formatFee = (partyId: string) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const isEmptyFeeObj = (feeObj: Schema.TradeFee) => {
|
||||
if (!feeObj) return true;
|
||||
return (
|
||||
feeObj.liquidityFee === '0' &&
|
||||
feeObj.makerFee === '0' &&
|
||||
feeObj.infrastructureFee === '0'
|
||||
);
|
||||
};
|
||||
|
||||
export const getRoleAndFees = ({
|
||||
data,
|
||||
partyId,
|
||||
@@ -232,14 +229,30 @@ export const getRoleAndFees = ({
|
||||
>;
|
||||
partyId?: string;
|
||||
}) => {
|
||||
let role;
|
||||
let role: Role;
|
||||
let feesObj;
|
||||
if (data?.buyer.id === partyId) {
|
||||
role = data.aggressor === Schema.Side.SIDE_BUY ? TAKER : MAKER;
|
||||
feesObj = role === TAKER ? data?.buyerFee : data.sellerFee;
|
||||
if (data.aggressor === Schema.Side.SIDE_BUY) {
|
||||
role = TAKER;
|
||||
feesObj = data?.buyerFee;
|
||||
} else if (data.aggressor === Schema.Side.SIDE_SELL) {
|
||||
role = MAKER;
|
||||
feesObj = data?.sellerFee;
|
||||
} else {
|
||||
role = '-';
|
||||
feesObj = !isEmptyFeeObj(data?.buyerFee) ? data.buyerFee : data.sellerFee;
|
||||
}
|
||||
} else if (data?.seller.id === partyId) {
|
||||
role = data.aggressor === Schema.Side.SIDE_SELL ? TAKER : MAKER;
|
||||
feesObj = role === TAKER ? data?.sellerFee : data.buyerFee;
|
||||
if (data.aggressor === Schema.Side.SIDE_SELL) {
|
||||
role = TAKER;
|
||||
feesObj = data?.sellerFee;
|
||||
} else if (data.aggressor === Schema.Side.SIDE_BUY) {
|
||||
role = MAKER;
|
||||
feesObj = data?.buyerFee;
|
||||
} else {
|
||||
role = '-';
|
||||
feesObj = !isEmptyFeeObj(data.sellerFee) ? data.sellerFee : data.buyerFee;
|
||||
}
|
||||
} else {
|
||||
return { role: '-', feesObj: '-' };
|
||||
}
|
||||
@@ -270,11 +283,6 @@ const FeesBreakdownTooltip = ({
|
||||
{role === MAKER && (
|
||||
<>
|
||||
<p className="mb-1">{t('The maker will receive the maker fee.')}</p>
|
||||
<p className="mb-1">
|
||||
{t(
|
||||
'If the market is in monitoring auction the maker will pay half of the infrastructure and liquidity fees.'
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-1">
|
||||
{t(
|
||||
'If the market is active the maker will pay zero infrastructure and liquidity fees.'
|
||||
@@ -283,14 +291,14 @@ const FeesBreakdownTooltip = ({
|
||||
</>
|
||||
)}
|
||||
{role === TAKER && (
|
||||
<>
|
||||
<p className="mb-1">{t('Fees to be paid by the taker.')}</p>
|
||||
<p className="mb-1">
|
||||
{t(
|
||||
'If the market is in monitoring auction the taker will pay half of the infrastructure and liquidity fees.'
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
<p className="mb-1">{t('Fees to be paid by the taker.')}</p>
|
||||
)}
|
||||
{role === '-' && (
|
||||
<p className="mb-1">
|
||||
{t(
|
||||
'If the market is in monitoring auction, half of the infrastructure and liquidity fees will be paid.'
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
<dl className="grid grid-cols-2 gap-x-1">
|
||||
<dt className="col-span-1">{t('Infrastructure fee')}</dt>
|
||||
@@ -316,7 +324,7 @@ const FeesBreakdownTooltip = ({
|
||||
};
|
||||
|
||||
export const getFeesBreakdown = (
|
||||
role: string,
|
||||
role: Role,
|
||||
feesObj: {
|
||||
__typename?: 'TradeFee' | undefined;
|
||||
makerFee: string;
|
||||
@@ -328,6 +336,7 @@ export const getFeesBreakdown = (
|
||||
role === MAKER
|
||||
? new BigNumber(feesObj.makerFee).times(-1).toString()
|
||||
: feesObj.makerFee;
|
||||
|
||||
const infrastructureFee = feesObj.infrastructureFee;
|
||||
const liquidityFee = feesObj.liquidityFee;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"name": "@vegaprotocol/react-helpers",
|
||||
"version": "0.2.0"
|
||||
"version": "0.1.0"
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { useRef } from 'react';
|
||||
import { BrowserTracing } from '@sentry/tracing';
|
||||
import * as Sentry from '@sentry/browser';
|
||||
import type { LocalLogger, LoggerConf } from '@vegaprotocol/utils';
|
||||
import type { LocalLogger } from '@vegaprotocol/utils';
|
||||
import { localLoggerFactory } from '@vegaprotocol/utils';
|
||||
|
||||
interface Props extends LoggerConf {
|
||||
interface Props {
|
||||
dsn?: string;
|
||||
application?: string;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export const useLogger = ({ dsn, ...props }: Props) => {
|
||||
|
||||
Generated
+271
-52
@@ -796,6 +796,67 @@ export type ETHAddress = {
|
||||
address?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
/** List of all entities created by transaction hash */
|
||||
export type Entities = {
|
||||
__typename?: 'Entities';
|
||||
/** List of accounts created by the transaction hash */
|
||||
accounts?: Maybe<Array<Maybe<AccountEvent>>>;
|
||||
/** List of assets created by the transaction hash */
|
||||
assets?: Maybe<Array<Maybe<Asset>>>;
|
||||
/** List of balance changes created by the transaction hash */
|
||||
balanceChanges?: Maybe<Array<Maybe<AccountBalance>>>;
|
||||
/** List of delegations created by the transaction hash */
|
||||
delegations?: Maybe<Array<Maybe<Delegation>>>;
|
||||
/** List of deposits created by the transaction hash */
|
||||
deposits?: Maybe<Array<Maybe<Deposit>>>;
|
||||
/** List of ERC-20 multisig signer added bundles created by the transaction hash */
|
||||
erc20MultiSigSignerAddedBundles?: Maybe<Array<Maybe<ERC20MultiSigSignerAddedBundle>>>;
|
||||
/** List of ERC-20 multisig signer removed bundles created by the transaction hash */
|
||||
erc20MultiSigSignerRemovedBundles?: Maybe<Array<Maybe<ERC20MultiSigSignerRemovedBundle>>>;
|
||||
/** List of ethereum key rotations created by the transaction hash */
|
||||
ethereumKeyRotations?: Maybe<Array<Maybe<EthereumKeyRotation>>>;
|
||||
/** List of key rotations created by the transaction hash */
|
||||
keyRotations?: Maybe<Array<Maybe<KeyRotation>>>;
|
||||
/** List of ledger entries created by the transaction hash */
|
||||
ledgerEntries?: Maybe<Array<Maybe<LedgerEntry>>>;
|
||||
/** List of liquidity provisions created by the transaction hash */
|
||||
liquidityProvisions?: Maybe<Array<Maybe<LiquidityProvision>>>;
|
||||
/** List of margin levels created by the transaction hash */
|
||||
marginLevels?: Maybe<Array<Maybe<MarginLevels>>>;
|
||||
/** List of markets created by the transaction hash */
|
||||
markets?: Maybe<Array<Maybe<Market>>>;
|
||||
/** List of network parameters created by the transaction hash */
|
||||
networkParameters?: Maybe<Array<Maybe<NetworkParameter>>>;
|
||||
/** List of node signatures created by the transaction hash */
|
||||
nodeSignatures?: Maybe<Array<Maybe<NodeSignature>>>;
|
||||
/** List of nodes created by the transaction hash */
|
||||
nodes?: Maybe<Array<Maybe<NodeBasic>>>;
|
||||
/** List of oracle data created by the transaction hash */
|
||||
oracleData?: Maybe<Array<Maybe<OracleData>>>;
|
||||
/** List of oracle specs created by the transaction hash */
|
||||
oracleSpecs?: Maybe<Array<Maybe<OracleSpec>>>;
|
||||
/** List of orders created by the transaction hash */
|
||||
orders?: Maybe<Array<Maybe<Order>>>;
|
||||
/** List of parties created by the transaction hash */
|
||||
parties?: Maybe<Array<Maybe<Party>>>;
|
||||
/** List of positions created by the transaction hash */
|
||||
positions?: Maybe<Array<Maybe<Position>>>;
|
||||
/** List of proposals created by the transaction hash */
|
||||
proposals?: Maybe<Array<Maybe<ProposalDetail>>>;
|
||||
/** List of protocol upgrade proposals created by the transaction hash */
|
||||
protocolUpgradeProposals?: Maybe<Array<Maybe<ProtocolUpgradeProposal>>>;
|
||||
/** List of rewards created by the transaction hash */
|
||||
rewards?: Maybe<Array<Maybe<Reward>>>;
|
||||
/** List of trades created by the transaction hash */
|
||||
trades?: Maybe<Array<Maybe<Trade>>>;
|
||||
/** List of transfers created by the transaction hash */
|
||||
transfers?: Maybe<Array<Maybe<Transfer>>>;
|
||||
/** List of votes created by the transaction hash */
|
||||
votes?: Maybe<Array<Maybe<Vote>>>;
|
||||
/** List of withdrawals created by the transaction hash */
|
||||
withdrawals?: Maybe<Array<Maybe<Withdrawal>>>;
|
||||
};
|
||||
|
||||
/** Epoch describes a specific period of time in the Vega network */
|
||||
export type Epoch = {
|
||||
__typename?: 'Epoch';
|
||||
@@ -988,6 +1049,15 @@ export type ExternalDataSourceSpec = {
|
||||
spec: DataSourceSpec;
|
||||
};
|
||||
|
||||
/** An estimate of the fee to be paid for the order */
|
||||
export type FeeEstimate = {
|
||||
__typename?: 'FeeEstimate';
|
||||
/** The estimated fees if the order was to trade */
|
||||
fees: TradeFee;
|
||||
/** The total estimated amount of fees if the order was to trade */
|
||||
totalFeeAmount: Scalars['String'];
|
||||
};
|
||||
|
||||
/** The factors applied to calculate the fees */
|
||||
export type FeeFactors = {
|
||||
__typename?: 'FeeFactors';
|
||||
@@ -1178,6 +1248,26 @@ export type LedgerEntryFilter = {
|
||||
TransferTypes?: InputMaybe<Array<InputMaybe<TransferType>>>;
|
||||
};
|
||||
|
||||
/** Liquidation estimate for both worst and best case possible */
|
||||
export type LiquidationEstimate = {
|
||||
__typename?: 'LiquidationEstimate';
|
||||
/** Liquidation price estimate assuming no slippage */
|
||||
bestCase: LiquidationPrice;
|
||||
/** Liquidation price estimate assuming slippage cap is applied */
|
||||
worstCase: LiquidationPrice;
|
||||
};
|
||||
|
||||
/** Liquidation price estimate for either only the current open volume and position given some or all buy orders get filled, or position given some or all sell orders get filled */
|
||||
export type LiquidationPrice = {
|
||||
__typename?: 'LiquidationPrice';
|
||||
/** Liquidation price assuming buy orders start getting filled */
|
||||
including_buy_orders: Scalars['String'];
|
||||
/** Liquidation price assuming sell orders start getting filled */
|
||||
including_sell_orders: Scalars['String'];
|
||||
/** Liquidation price for current open volume ignoring any active orders */
|
||||
open_volume_only: Scalars['String'];
|
||||
};
|
||||
|
||||
/** Configuration of a market liquidity monitoring parameters */
|
||||
export type LiquidityMonitoringParameters = {
|
||||
__typename?: 'LiquidityMonitoringParameters';
|
||||
@@ -1367,6 +1457,15 @@ export type MarginEdge = {
|
||||
node: MarginLevels;
|
||||
};
|
||||
|
||||
/** Margin level estimate for both worst and best case possible */
|
||||
export type MarginEstimate = {
|
||||
__typename?: 'MarginEstimate';
|
||||
/** Margin level estimate assuming no slippage */
|
||||
bestCase: MarginLevels;
|
||||
/** Margin level estimate assuming slippage cap is applied */
|
||||
worstCase: MarginLevels;
|
||||
};
|
||||
|
||||
/** Margins for a given a party */
|
||||
export type MarginLevels = {
|
||||
__typename?: 'MarginLevels';
|
||||
@@ -1377,7 +1476,7 @@ export type MarginLevels = {
|
||||
* the general account of the party for the given asset.
|
||||
*/
|
||||
collateralReleaseLevel: Scalars['String'];
|
||||
/** This is the minimum margin required for a party to place a new order on the network (unsigned integer) */
|
||||
/** This is the minimum margin required for a party to place a new order on the network, expressed as unsigned integer */
|
||||
initialLevel: Scalars['String'];
|
||||
/** Minimal margin for the position to be maintained in the network (unsigned integer) */
|
||||
maintenanceLevel: Scalars['String'];
|
||||
@@ -1385,7 +1484,7 @@ export type MarginLevels = {
|
||||
market: Market;
|
||||
/** The party for this margin */
|
||||
party: Party;
|
||||
/** If the margin is between maintenance and search, the network will initiate a collateral search (unsigned integer) */
|
||||
/** If the margin is between maintenance and search, the network will initiate a collateral search, expressed as unsigned integer */
|
||||
searchLevel: Scalars['String'];
|
||||
/** RFC3339Nano time from at which this margin level was relevant */
|
||||
timestamp: Scalars['Timestamp'];
|
||||
@@ -1483,6 +1582,7 @@ export type Market = {
|
||||
state: MarketState;
|
||||
/** An instance of, or reference to, a tradable instrument. */
|
||||
tradableInstrument: TradableInstrument;
|
||||
/** @deprecated Simplify and consolidate trades query and remove nesting. Use trades query instead */
|
||||
tradesConnection?: Maybe<TradeConnection>;
|
||||
/** Current mode of execution of the market */
|
||||
tradingMode: MarketTradingMode;
|
||||
@@ -1894,6 +1994,28 @@ export type NodedelegationsConnectionArgs = {
|
||||
partyId?: InputMaybe<Scalars['ID']>;
|
||||
};
|
||||
|
||||
export type NodeBasic = {
|
||||
__typename?: 'NodeBasic';
|
||||
/** The URL of an avatar */
|
||||
avatarUrl?: Maybe<Scalars['String']>;
|
||||
/** Ethereum public key of the node */
|
||||
ethereumAddress: Scalars['String'];
|
||||
/** The node URL, for example n01.vega.xyz */
|
||||
id: Scalars['ID'];
|
||||
/** URL that provides more information about the node */
|
||||
infoUrl: Scalars['String'];
|
||||
/** Country code for the location of the node */
|
||||
location: Scalars['String'];
|
||||
/** The name of the node operator */
|
||||
name: Scalars['String'];
|
||||
/** Public key of the node operator */
|
||||
pubkey: Scalars['String'];
|
||||
/** Validator status of the node */
|
||||
status: NodeStatus;
|
||||
/** Tendermint public key of the node */
|
||||
tmPubkey: Scalars['String'];
|
||||
};
|
||||
|
||||
/** Summary of data across all nodes */
|
||||
export type NodeData = {
|
||||
__typename?: 'NodeData';
|
||||
@@ -2107,18 +2229,6 @@ export type ObservableMarketDepthUpdate = {
|
||||
sequenceNumber: Scalars['String'];
|
||||
};
|
||||
|
||||
export type OffsetPagination = {
|
||||
/**
|
||||
* Descending reverses the order of the records returned
|
||||
* default is true, if false the results will be returned in ascending order
|
||||
*/
|
||||
descending: Scalars['Boolean'];
|
||||
/** Limit the number of returned records to the value specified, default is 50 */
|
||||
limit: Scalars['Int'];
|
||||
/** Skip the number of records specified, default is 0 */
|
||||
skip: Scalars['Int'];
|
||||
};
|
||||
|
||||
/** The specific details for a one-off transfer */
|
||||
export type OneOffTransfer = {
|
||||
__typename?: 'OneOffTransfer';
|
||||
@@ -2213,7 +2323,10 @@ export type Order = {
|
||||
status: OrderStatus;
|
||||
/** The timeInForce of order (determines how and if it executes, and whether it persists on the book) */
|
||||
timeInForce: OrderTimeInForce;
|
||||
/** Trades relating to this order */
|
||||
/**
|
||||
* Trades relating to this order
|
||||
* @deprecated Simplify and consolidate trades query and remove nesting. Use trades query instead
|
||||
*/
|
||||
tradesConnection?: Maybe<TradeConnection>;
|
||||
/** The order type */
|
||||
type?: Maybe<OrderType>;
|
||||
@@ -2279,11 +2392,28 @@ export type OrderFilter = {
|
||||
/** Date range to retrieve orders from/to. Start and end time should be expressed as an integer value of nano-seconds past the Unix epoch */
|
||||
dateRange?: InputMaybe<DateRange>;
|
||||
excludeLiquidity?: InputMaybe<Scalars['Boolean']>;
|
||||
/**
|
||||
* If true, only orders that are live will be returned. Orders are live if they have STATUS_ACTIVE or STATUS_PARKED
|
||||
* as per https://github.com/vegaprotocol/specs-internal/blob/master/protocol/0024-OSTA-order_status.md
|
||||
*/
|
||||
liveOnly?: InputMaybe<Scalars['Boolean']>;
|
||||
status?: InputMaybe<Array<OrderStatus>>;
|
||||
timeInForce?: InputMaybe<Array<OrderTimeInForce>>;
|
||||
types?: InputMaybe<Array<OrderType>>;
|
||||
};
|
||||
|
||||
/** Basic description of an order */
|
||||
export type OrderInfo = {
|
||||
/** Boolean indicating a market order */
|
||||
isMarketOrder: Scalars['Boolean'];
|
||||
/** Price for the order */
|
||||
price: Scalars['String'];
|
||||
/** Number of units remaining of the total that have not yet been bought or sold (uint64) */
|
||||
remaining: Scalars['String'];
|
||||
/** Whether the order is to buy or sell */
|
||||
side: Side;
|
||||
};
|
||||
|
||||
/** Why the order was rejected by the core node */
|
||||
export enum OrderRejectionReason {
|
||||
/** Amending the order failed */
|
||||
@@ -2304,6 +2434,8 @@ export enum OrderRejectionReason {
|
||||
ORDER_ERROR_CANNOT_HAVE_GTC_AND_EXPIRYAT = 'ORDER_ERROR_CANNOT_HAVE_GTC_AND_EXPIRYAT',
|
||||
/** Cannot send FOK orders during an auction */
|
||||
ORDER_ERROR_CANNOT_SEND_FOK_ORDER_DURING_AUCTION = 'ORDER_ERROR_CANNOT_SEND_FOK_ORDER_DURING_AUCTION',
|
||||
/** Good for Auction order received during continuous trading */
|
||||
ORDER_ERROR_CANNOT_SEND_GFA_ORDER_DURING_CONTINUOUS_TRADING = 'ORDER_ERROR_CANNOT_SEND_GFA_ORDER_DURING_CONTINUOUS_TRADING',
|
||||
/** Good for Normal order received during an auction */
|
||||
ORDER_ERROR_CANNOT_SEND_GFN_ORDER_DURING_AN_AUCTION = 'ORDER_ERROR_CANNOT_SEND_GFN_ORDER_DURING_AN_AUCTION',
|
||||
/** Cannot send IOC orders during an auction */
|
||||
@@ -2312,8 +2444,8 @@ export enum OrderRejectionReason {
|
||||
ORDER_ERROR_EDIT_NOT_ALLOWED = 'ORDER_ERROR_EDIT_NOT_ALLOWED',
|
||||
/** Attempt to amend expiry time to a value before time order was created */
|
||||
ORDER_ERROR_EXPIRYAT_BEFORE_CREATEDAT = 'ORDER_ERROR_EXPIRYAT_BEFORE_CREATEDAT',
|
||||
/** Good for Auction order received during continuous trading */
|
||||
ORDER_ERROR_GFA_CANNOT_SEND_ORDER_DURING_CONTINUOUS_TRADING = 'ORDER_ERROR_GFA_CANNOT_SEND_ORDER_DURING_CONTINUOUS_TRADING',
|
||||
/** Order was submitted with an incorrect or invalid market type */
|
||||
ORDER_ERROR_INCORRECT_MARKET_TYPE = 'ORDER_ERROR_INCORRECT_MARKET_TYPE',
|
||||
/** Insufficient balance to submit the order (no deposit made) */
|
||||
ORDER_ERROR_INSUFFICIENT_ASSET_BALANCE = 'ORDER_ERROR_INSUFFICIENT_ASSET_BALANCE',
|
||||
/** Insufficient funds to pay fees */
|
||||
@@ -2360,6 +2492,10 @@ export enum OrderRejectionReason {
|
||||
ORDER_ERROR_OFFSET_MUST_BE_GREATER_THAN_ZERO = 'ORDER_ERROR_OFFSET_MUST_BE_GREATER_THAN_ZERO',
|
||||
/** Order is out of sequence */
|
||||
ORDER_ERROR_OUT_OF_SEQUENCE = 'ORDER_ERROR_OUT_OF_SEQUENCE',
|
||||
/** A post-only order would produce an aggressive trade and thus it has been rejected */
|
||||
ORDER_ERROR_POST_ONLY_ORDER_WOULD_TRADE = 'ORDER_ERROR_POST_ONLY_ORDER_WOULD_TRADE',
|
||||
/** A reduce-ony order would not reduce the party's position and thus it has been rejected */
|
||||
ORDER_ERROR_REDUCE_ONLY_ORDER_WOULD_NOT_REDUCE = 'ORDER_ERROR_REDUCE_ONLY_ORDER_WOULD_NOT_REDUCE',
|
||||
/** Unable to remove the order */
|
||||
ORDER_ERROR_REMOVAL_FAILURE = 'ORDER_ERROR_REMOVAL_FAILURE',
|
||||
/** Order cannot be filled because it would require self trading */
|
||||
@@ -2368,6 +2504,8 @@ export enum OrderRejectionReason {
|
||||
ORDER_ERROR_SELL_CANNOT_REFERENCE_BEST_BID_PRICE = 'ORDER_ERROR_SELL_CANNOT_REFERENCE_BEST_BID_PRICE',
|
||||
/** Time has failed us */
|
||||
ORDER_ERROR_TIME_FAILURE = 'ORDER_ERROR_TIME_FAILURE',
|
||||
/** Unable to submit pegged order, temporarily too many pegged orders across all markets */
|
||||
ORDER_ERROR_TOO_MANY_PEGGED_ORDERS = 'ORDER_ERROR_TOO_MANY_PEGGED_ORDERS',
|
||||
/** Unable to amend pegged order price */
|
||||
ORDER_ERROR_UNABLE_TO_AMEND_PRICE_ON_PEGGED_ORDER = 'ORDER_ERROR_UNABLE_TO_AMEND_PRICE_ON_PEGGED_ORDER',
|
||||
/** Unable to reprice a pegged order */
|
||||
@@ -2526,6 +2664,7 @@ export type Party = {
|
||||
rewardsConnection?: Maybe<RewardsConnection>;
|
||||
/** The staking information for this Party */
|
||||
stakingSummary: StakingSummary;
|
||||
/** @deprecated Simplify and consolidate trades query and remove nesting. Use trades query instead */
|
||||
tradesConnection?: Maybe<TradeConnection>;
|
||||
/** All transfers for a public key */
|
||||
transfersConnection?: Maybe<TransferConnection>;
|
||||
@@ -2754,6 +2893,15 @@ export type PositionEdge = {
|
||||
node: Position;
|
||||
};
|
||||
|
||||
/** Response for the estimate of the margin level and, if available, collateral was provided in the request, liqudation price for the specified position */
|
||||
export type PositionEstimate = {
|
||||
__typename?: 'PositionEstimate';
|
||||
/** Liquidation price range estimate for the specified position. Only populated if available collateral was specified in the request */
|
||||
liquidation?: Maybe<LiquidationEstimate>;
|
||||
/** Margin level range estimate for the specified position */
|
||||
margin: MarginEstimate;
|
||||
};
|
||||
|
||||
export type PositionResolution = {
|
||||
__typename?: 'PositionResolution';
|
||||
/** Number of parties closed out */
|
||||
@@ -2770,6 +2918,8 @@ export type PositionResolution = {
|
||||
export enum PositionStatus {
|
||||
/** The position was distressed, and had to be closed out entirely - orders were removed from the book, and the open volume was closed out by the network */
|
||||
POSITION_STATUS_CLOSED_OUT = 'POSITION_STATUS_CLOSED_OUT',
|
||||
/** The position was distressed, but could not be closed out - orders were removed from the book, and the open volume will be closed out once there is sufficient volume on the book */
|
||||
POSITION_STATUS_DISTRESSED = 'POSITION_STATUS_DISTRESSED',
|
||||
/** The position was distressed, but removing open orders from the book brought the margin level back to a point where the open position could be maintained */
|
||||
POSITION_STATUS_ORDERS_CLOSED = 'POSITION_STATUS_ORDERS_CLOSED',
|
||||
/** The position is either healthy, or if closed out, was closed out normally */
|
||||
@@ -2923,9 +3073,9 @@ export type Proposal = {
|
||||
reference: Scalars['String'];
|
||||
/** Why the proposal was rejected by the core */
|
||||
rejectionReason?: Maybe<ProposalRejectionReason>;
|
||||
/** Required liquidity provider equity like share majority for this proposal to succeed */
|
||||
/** Equity-like share required for a market amendment proposal to be enacted (if not met, the proposal will not be enacted), represented as a fraction that can be converted to a percentage */
|
||||
requiredLpMajority?: Maybe<Scalars['String']>;
|
||||
/** Required liquidity provider equity like share participation for this proposal to succeed */
|
||||
/** The market share of LPs' equity-like share that must take part in the market amendment vote for the proposal to pass. This means the votes of LPs that have submitted more liquidity to that market, or have been LPs from the start carry more weight. If it requires 50% of a market's equity-like share for a majority, and the proposal receives only YES votes but only LPs with 49% of the equity-like share voted, the proposal will not pass */
|
||||
requiredLpParticipation?: Maybe<Scalars['String']>;
|
||||
/** Required majority for this proposal to succeed */
|
||||
requiredMajority: Scalars['String'];
|
||||
@@ -2941,6 +3091,36 @@ export type Proposal = {
|
||||
|
||||
export type ProposalChange = NewAsset | NewFreeform | NewMarket | UpdateAsset | UpdateMarket | UpdateNetworkParameter;
|
||||
|
||||
export type ProposalDetail = {
|
||||
__typename?: 'ProposalDetail';
|
||||
/** RFC3339Nano time and date when the proposal reached the Vega network */
|
||||
datetime: Scalars['Timestamp'];
|
||||
/** Error details of the rejectionReason */
|
||||
errorDetails?: Maybe<Scalars['String']>;
|
||||
/** Proposal ID that is provided by Vega once proposal reaches the network */
|
||||
id?: Maybe<Scalars['ID']>;
|
||||
/** Party that prepared the proposal */
|
||||
party: Party;
|
||||
/** Rationale behind the proposal */
|
||||
rationale: ProposalRationale;
|
||||
/** A UUID reference to aid tracking proposals on Vega */
|
||||
reference: Scalars['String'];
|
||||
/** Why the proposal was rejected by the core */
|
||||
rejectionReason?: Maybe<ProposalRejectionReason>;
|
||||
/** Equity-like share required for a market amendment proposal to be enacted (if not met, the proposal will not be enacted), represented as a fraction that can be converted to a percentage */
|
||||
requiredLpMajority?: Maybe<Scalars['String']>;
|
||||
/** The market share of LPs' equity-like share that must take part in the market amendment vote for the proposal to pass. This means the votes of LPs that have submitted more liquidity to that market, or have been LPs from the start carry more weight. If it requires 50% of a market's equity-like share for a majority, and the proposal receives only YES votes but only LPs with 49% of the equity-like share voted, the proposal will not pass */
|
||||
requiredLpParticipation?: Maybe<Scalars['String']>;
|
||||
/** Required majority for this proposal to succeed */
|
||||
requiredMajority: Scalars['String'];
|
||||
/** Required participation for this proposal to succeed */
|
||||
requiredParticipation: Scalars['String'];
|
||||
/** State of the proposal */
|
||||
state: ProposalState;
|
||||
/** Terms of the proposal */
|
||||
terms: ProposalTerms;
|
||||
};
|
||||
|
||||
/** Edge type containing the proposals and cursor information returned by a ProposalsConnection */
|
||||
export type ProposalEdge = {
|
||||
__typename?: 'ProposalEdge';
|
||||
@@ -3234,6 +3414,8 @@ export type Query = {
|
||||
deposit?: Maybe<Deposit>;
|
||||
/** Fetch all deposits */
|
||||
deposits?: Maybe<DepositsConnection>;
|
||||
/** Fetch all entities for a given transaction hash */
|
||||
entities: Entities;
|
||||
/** Get data for a specific epoch, if ID omitted it gets the current epoch. If the string is 'next', fetch the next epoch */
|
||||
epoch: Epoch;
|
||||
/** List reward summary per epoch by asset, market, reward type */
|
||||
@@ -3249,15 +3431,17 @@ export type Query = {
|
||||
/** Find an erc20 withdrawal approval using its withdrawal ID */
|
||||
erc20WithdrawalApproval?: Maybe<Erc20WithdrawalApproval>;
|
||||
/** Return an estimation of the potential cost for a new order */
|
||||
estimateFees: FeeEstimate;
|
||||
/**
|
||||
* Return an estimation of the potential cost for a new order
|
||||
* @deprecated Use estimateFees and estimatePosition instead
|
||||
*/
|
||||
estimateOrder: OrderEstimate;
|
||||
/** Return a margin range for the specified position and liquidation price range if available collateral is supplied */
|
||||
estimatePosition?: Maybe<PositionEstimate>;
|
||||
/** Query for historic ethereum key rotations */
|
||||
ethereumKeyRotations: EthereumKeyRotationsConnection;
|
||||
/**
|
||||
* Get market data history for a specific market. If no dates are given, the latest snapshot will be returned. If only the start date is provided, all history from the given date will be provided, and if only the end date is provided, all history from the start up to and including the end date will be provided.
|
||||
* @deprecated Use getMarketDataHistoryConnectionByID instead
|
||||
*/
|
||||
getMarketDataHistoryByID?: Maybe<Array<Maybe<MarketData>>>;
|
||||
/** Get market data history for a specific market. If no dates are given, the latest snapshot will be returned. If only the start date is provided all history from the given date will be provided, and if only the end date is provided, all history from the start up to and including the end date will be provided. Pagination is provided using a cursor based pagination model */
|
||||
/** Get market data history for a specific market. If no dates are given, the latest snapshot will be returned. If only the start date is provided all history from the given date will be provided, and if only the end date is provided, all history from the start up to and including the end date will be provided. */
|
||||
getMarketDataHistoryConnectionByID?: Maybe<MarketDataConnection>;
|
||||
/** Query for historic key rotations */
|
||||
keyRotationsConnection: KeyRotationConnection;
|
||||
@@ -3315,6 +3499,8 @@ export type Query = {
|
||||
protocolUpgradeStatus?: Maybe<ProtocolUpgradeStatus>;
|
||||
/** Get statistics about the Vega node */
|
||||
statistics: Statistics;
|
||||
/** Get a list of all trades and apply any given filters to the results */
|
||||
trades?: Maybe<TradeConnection>;
|
||||
/** Get a list of all transfers for a public key */
|
||||
transfersConnection?: Maybe<TransferConnection>;
|
||||
/** Find a withdrawal using its ID */
|
||||
@@ -3364,6 +3550,12 @@ export type QuerydepositsArgs = {
|
||||
};
|
||||
|
||||
|
||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||
export type QueryentitiesArgs = {
|
||||
txHash: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||
export type QueryepochArgs = {
|
||||
id?: InputMaybe<Scalars['ID']>;
|
||||
@@ -3413,6 +3605,19 @@ export type Queryerc20WithdrawalApprovalArgs = {
|
||||
};
|
||||
|
||||
|
||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||
export type QueryestimateFeesArgs = {
|
||||
expiration?: InputMaybe<Scalars['Timestamp']>;
|
||||
marketId: Scalars['ID'];
|
||||
partyId: Scalars['ID'];
|
||||
price?: InputMaybe<Scalars['String']>;
|
||||
side: Side;
|
||||
size: Scalars['String'];
|
||||
timeInForce: OrderTimeInForce;
|
||||
type: OrderType;
|
||||
};
|
||||
|
||||
|
||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||
export type QueryestimateOrderArgs = {
|
||||
expiration?: InputMaybe<Scalars['Timestamp']>;
|
||||
@@ -3427,19 +3632,17 @@ export type QueryestimateOrderArgs = {
|
||||
|
||||
|
||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||
export type QueryethereumKeyRotationsArgs = {
|
||||
nodeId?: InputMaybe<Scalars['ID']>;
|
||||
export type QueryestimatePositionArgs = {
|
||||
collateralAvailable?: InputMaybe<Scalars['String']>;
|
||||
marketId: Scalars['ID'];
|
||||
openVolume: Scalars['String'];
|
||||
orders?: InputMaybe<Array<OrderInfo>>;
|
||||
};
|
||||
|
||||
|
||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||
export type QuerygetMarketDataHistoryByIDArgs = {
|
||||
end?: InputMaybe<Scalars['Timestamp']>;
|
||||
first?: InputMaybe<Scalars['Int']>;
|
||||
id: Scalars['ID'];
|
||||
last?: InputMaybe<Scalars['Int']>;
|
||||
skip?: InputMaybe<Scalars['Int']>;
|
||||
start?: InputMaybe<Scalars['Timestamp']>;
|
||||
export type QueryethereumKeyRotationsArgs = {
|
||||
nodeId?: InputMaybe<Scalars['ID']>;
|
||||
};
|
||||
|
||||
|
||||
@@ -3600,6 +3803,14 @@ export type QueryprotocolUpgradeProposalsArgs = {
|
||||
};
|
||||
|
||||
|
||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||
export type QuerytradesArgs = {
|
||||
dateRange?: InputMaybe<DateRange>;
|
||||
filter?: InputMaybe<TradesFilter>;
|
||||
pagination?: InputMaybe<Pagination>;
|
||||
};
|
||||
|
||||
|
||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||
export type QuerytransfersConnectionArgs = {
|
||||
direction?: InputMaybe<TransferDirection>;
|
||||
@@ -3798,7 +4009,9 @@ export enum Side {
|
||||
/** The placer of the order is aiming to buy */
|
||||
SIDE_BUY = 'SIDE_BUY',
|
||||
/** The placer of the order is aiming to sell */
|
||||
SIDE_SELL = 'SIDE_SELL'
|
||||
SIDE_SELL = 'SIDE_SELL',
|
||||
/** Unspecified is only used for trades at the end of an auction, where neither party acts as the aggressor. */
|
||||
SIDE_UNSPECIFIED = 'SIDE_UNSPECIFIED'
|
||||
}
|
||||
|
||||
/** Signer is the authorized signature used for the data. */
|
||||
@@ -3978,8 +4191,6 @@ export type Subscription = {
|
||||
busEvents?: Maybe<Array<BusEvent>>;
|
||||
/** Subscribe to the candles updates */
|
||||
candles: Candle;
|
||||
/** Subscribe to delegation data */
|
||||
delegations: Delegation;
|
||||
/** Subscribe to liquidity provisioning data */
|
||||
liquidityProvisions?: Maybe<Array<LiquidityProvisionUpdate>>;
|
||||
/** Subscribe to the margin changes */
|
||||
@@ -3996,10 +4207,13 @@ export type Subscription = {
|
||||
positions: Array<PositionUpdate>;
|
||||
/** Subscribe to proposals. Leave out all arguments to receive all proposals */
|
||||
proposals: Proposal;
|
||||
/** Subscribe to reward details data */
|
||||
rewards: Reward;
|
||||
/** Subscribe to the trades updates */
|
||||
/**
|
||||
* Subscribe to the trades updates
|
||||
* @deprecated Use tradesStream instead as it allows for filtering multiple markets and/or parties at once
|
||||
*/
|
||||
trades?: Maybe<Array<TradeUpdate>>;
|
||||
/** Subscribe to the trades updates */
|
||||
tradesStream?: Maybe<Array<TradeUpdate>>;
|
||||
/** Subscribe to votes, either by proposal ID or party ID */
|
||||
votes: ProposalVote;
|
||||
};
|
||||
@@ -4030,13 +4244,6 @@ export type SubscriptioncandlesArgs = {
|
||||
};
|
||||
|
||||
|
||||
/** Subscriptions allow a caller to receive new information as it is available from the Vega network. */
|
||||
export type SubscriptiondelegationsArgs = {
|
||||
nodeId?: InputMaybe<Scalars['ID']>;
|
||||
partyId?: InputMaybe<Scalars['ID']>;
|
||||
};
|
||||
|
||||
|
||||
/** Subscriptions allow a caller to receive new information as it is available from the Vega network. */
|
||||
export type SubscriptionliquidityProvisionsArgs = {
|
||||
marketId?: InputMaybe<Scalars['ID']>;
|
||||
@@ -4089,16 +4296,15 @@ export type SubscriptionproposalsArgs = {
|
||||
|
||||
|
||||
/** Subscriptions allow a caller to receive new information as it is available from the Vega network. */
|
||||
export type SubscriptionrewardsArgs = {
|
||||
assetId?: InputMaybe<Scalars['ID']>;
|
||||
export type SubscriptiontradesArgs = {
|
||||
marketId?: InputMaybe<Scalars['ID']>;
|
||||
partyId?: InputMaybe<Scalars['ID']>;
|
||||
};
|
||||
|
||||
|
||||
/** Subscriptions allow a caller to receive new information as it is available from the Vega network. */
|
||||
export type SubscriptiontradesArgs = {
|
||||
marketId?: InputMaybe<Scalars['ID']>;
|
||||
partyId?: InputMaybe<Scalars['ID']>;
|
||||
export type SubscriptiontradesStreamArgs = {
|
||||
filter: TradesSubscriptionFilter;
|
||||
};
|
||||
|
||||
|
||||
@@ -4251,6 +4457,19 @@ export type TradeUpdate = {
|
||||
type: TradeType;
|
||||
};
|
||||
|
||||
/** Filter to apply to the trade connection query */
|
||||
export type TradesFilter = {
|
||||
marketIds?: InputMaybe<Array<Scalars['ID']>>;
|
||||
orderIds?: InputMaybe<Array<Scalars['ID']>>;
|
||||
partyIds?: InputMaybe<Array<Scalars['ID']>>;
|
||||
};
|
||||
|
||||
/** Filter to apply to the trade subscription request */
|
||||
export type TradesSubscriptionFilter = {
|
||||
marketIds?: InputMaybe<Array<Scalars['ID']>>;
|
||||
partyIds?: InputMaybe<Array<Scalars['ID']>>;
|
||||
};
|
||||
|
||||
/** The result from processing a transaction */
|
||||
export type TransactionResult = {
|
||||
__typename?: 'TransactionResult';
|
||||
|
||||
@@ -172,7 +172,7 @@ export const OrderRejectionReasonMapping: {
|
||||
'Cannot send IOC order during auction',
|
||||
ORDER_ERROR_EDIT_NOT_ALLOWED: 'Edit not allowed',
|
||||
ORDER_ERROR_EXPIRYAT_BEFORE_CREATEDAT: 'Expiry time before creation time',
|
||||
ORDER_ERROR_GFA_CANNOT_SEND_ORDER_DURING_CONTINUOUS_TRADING:
|
||||
ORDER_ERROR_CANNOT_SEND_GFA_ORDER_DURING_CONTINUOUS_TRADING:
|
||||
'Cannot send GFA order during continuous trading',
|
||||
ORDER_ERROR_INSUFFICIENT_ASSET_BALANCE: 'Insufficient asset balance',
|
||||
ORDER_ERROR_INSUFFICIENT_FUNDS_TO_PAY_FEES: 'Insufficient funds to pay fees',
|
||||
@@ -209,6 +209,11 @@ export const OrderRejectionReasonMapping: {
|
||||
'Unable to amend price on pegged order',
|
||||
ORDER_ERROR_UNABLE_TO_REPRICE_PEGGED_ORDER: 'Unable to reprice pegged order',
|
||||
ORDER_ERROR_WITHOUT_REFERENCE_PRICE: 'Without reference price',
|
||||
ORDER_ERROR_INCORRECT_MARKET_TYPE: 'Incorrect market type',
|
||||
ORDER_ERROR_POST_ONLY_ORDER_WOULD_TRADE: 'Post only order would trade',
|
||||
ORDER_ERROR_REDUCE_ONLY_ORDER_WOULD_NOT_REDUCE:
|
||||
'Reduce only order would not reduce',
|
||||
ORDER_ERROR_TOO_MANY_PEGGED_ORDERS: 'Too many pegged orders',
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -345,6 +350,7 @@ export const SideMapping: {
|
||||
} = {
|
||||
SIDE_BUY: 'Long',
|
||||
SIDE_SELL: 'Short',
|
||||
SIDE_UNSPECIFIED: 'Unspecified',
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -458,6 +464,7 @@ export const PositionStatusMapping: {
|
||||
POSITION_STATUS_CLOSED_OUT: 'Closed by network',
|
||||
POSITION_STATUS_ORDERS_CLOSED: 'Maintained by network',
|
||||
POSITION_STATUS_UNSPECIFIED: 'Normal',
|
||||
POSITION_STATUS_DISTRESSED: 'Distressed',
|
||||
};
|
||||
|
||||
export const ConditionOperatorMapping: { [C in ConditionOperator]: string } = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"name": "@vegaprotocol/ui-toolkit",
|
||||
"version": "0.11.0"
|
||||
"version": "0.9.0"
|
||||
}
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import {
|
||||
truncateByChars,
|
||||
ELLIPSIS,
|
||||
shorten,
|
||||
titlefy,
|
||||
stripFullStops,
|
||||
} from './strings';
|
||||
import { truncateByChars, ELLIPSIS, shorten, titlefy } from './strings';
|
||||
|
||||
describe('truncateByChars', () => {
|
||||
it.each([
|
||||
@@ -55,35 +49,3 @@ describe('titlefy', () => {
|
||||
expect(titlefy(words)).toEqual(o);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stripFullStops', () => {
|
||||
describe('stripFullStops', () => {
|
||||
it('removes full stops from a version string', () => {
|
||||
const input = 'v0.70.0-12075-8fa496c8';
|
||||
const expectedResult = 'v0700-12075-8fa496c8';
|
||||
expect(stripFullStops(input)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('does not alter a string without full stops', () => {
|
||||
const input = 'v0700-12075-8fa496c8';
|
||||
expect(stripFullStops(input)).toBe(input);
|
||||
});
|
||||
|
||||
it('removes full stops from a string with consecutive full stops', () => {
|
||||
const input = 'v0..70...0-12075-8fa496c8';
|
||||
const expectedResult = 'v0700-12075-8fa496c8';
|
||||
expect(stripFullStops(input)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('removes full stops from a string with only full stops', () => {
|
||||
const input = '..........';
|
||||
const expectedResult = '';
|
||||
expect(stripFullStops(input)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('does not alter an empty string', () => {
|
||||
const input = '';
|
||||
expect(stripFullStops(input)).toBe(input);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,7 +26,3 @@ export function titlefy(words: (string | null | undefined)[]) {
|
||||
.join(TITLE_SEPARATOR);
|
||||
return title;
|
||||
}
|
||||
|
||||
export function stripFullStops(input: string) {
|
||||
return input.replace(/\./g, '');
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ type ConsoleMethod = {
|
||||
}[keyof Console] &
|
||||
string;
|
||||
|
||||
export interface LoggerConf {
|
||||
interface LoggerConf {
|
||||
application?: string;
|
||||
tags?: string[];
|
||||
logLevel?: LogLevelsType;
|
||||
|
||||
Reference in New Issue
Block a user