Compare commits

..
Author SHA1 Message Date
bwallacee 477f0a06ff chore(trading): remove fixture usage 2024-02-26 13:16:01 +00:00
bwallacee beaed2e133 chore(trading): ci test 2024-02-26 11:04:26 +00:00
386 changed files with 8168 additions and 5906 deletions
+36
View File
@@ -0,0 +1,36 @@
name: Cypress Console tests -- live environment
# This workflow runs using provided url
on:
workflow_dispatch:
inputs:
url:
description: 'Url'
required: true
type: string
jobs:
cypress-run:
name: Run Cypress Trading tests -- live environment
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Use Node.js 20
id: Node
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Run Cypress tests
uses: cypress-io/github-action@v4
with:
browser: chrome
record: true
project: ./apps/trading-e2e
config: baseUrl=${{ github.event.inputs.url }}
env: grepTags=@live
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -12,6 +12,7 @@ on:
options:
- explorer-e2e
- governance-e2e
- trading-e2e
tags:
description: 'Test tags to run'
required: true
+1 -1
View File
@@ -10,5 +10,5 @@ jobs:
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
with:
projects: '["explorer-e2e","governance-e2e"]'
projects: '["explorer-e2e","governance-e2e","trading-e2e"]'
tags: '@smoke @regression @slow'
+2 -2
View File
@@ -25,7 +25,7 @@ jobs:
- name: Install dependencies
run: |
rm package.json
npm install --no-save @commitlint/cli@16.3.0 @commitlint/config-conventional@18.6.1 @commitlint/config-nx-scopes@18.6.1 nx@17.1.2
npm install --no-save @commitlint/cli @commitlint/config-conventional @commitlint/config-nx-scopes nx
- name: Check PR title
run: echo "${{ github.event.pull_request.title }}" | npx @commitlint/cli@16.3.0 --config ./commitlint.config-ci.js
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
@@ -8,14 +8,12 @@ import EpochMissingOverview from './epoch-missing';
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
import type { IconProps } from '@vegaprotocol/ui-toolkit';
import isPast from 'date-fns/isPast';
import { EpochSymbol } from '../links/block-link/block-link';
const borderClass =
'border-solid border-2 border-vega-dark-200 border-collapse';
export type EpochOverviewProps = {
id?: string;
icon?: boolean;
};
/**
@@ -26,7 +24,7 @@ export type EpochOverviewProps = {
*
* The details are hidden in a tooltip, behind the epoch number
*/
const EpochOverview = ({ id, icon = true }: EpochOverviewProps) => {
const EpochOverview = ({ id }: EpochOverviewProps) => {
const { data, error, loading } = useExplorerEpochQuery({
variables: { id: id || '' },
});
@@ -40,12 +38,7 @@ const EpochOverview = ({ id, icon = true }: EpochOverviewProps) => {
}
if (!ti || loading || error) {
return (
<span>
<EpochSymbol />
{id}
</span>
);
return <span>{id}</span>;
}
const description = (
@@ -97,11 +90,7 @@ const EpochOverview = ({ id, icon = true }: EpochOverviewProps) => {
return (
<Tooltip description={description}>
<p>
{icon ? (
<IconForEpoch start={ti.start} end={ti.end} />
) : (
<EpochSymbol />
)}
<IconForEpoch start={ti.start} end={ti.end} />
{id}
</p>
</Tooltip>
@@ -1,10 +0,0 @@
query ExplorerEpochForBlock($block: String!) {
epoch(block: $block) {
id
timestamps {
start
end
lastBlock
}
}
}
@@ -1,53 +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 ExplorerEpochForBlockQueryVariables = Types.Exact<{
block: Types.Scalars['String'];
}>;
export type ExplorerEpochForBlockQuery = { __typename?: 'Query', epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, lastBlock?: string | null } } };
export const ExplorerEpochForBlockDocument = gql`
query ExplorerEpochForBlock($block: String!) {
epoch(block: $block) {
id
timestamps {
start
end
lastBlock
}
}
}
`;
/**
* __useExplorerEpochForBlockQuery__
*
* To run a query within a React component, call `useExplorerEpochForBlockQuery` and pass it any options that fit your needs.
* When your component renders, `useExplorerEpochForBlockQuery` 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 } = useExplorerEpochForBlockQuery({
* variables: {
* block: // value for 'block'
* },
* });
*/
export function useExplorerEpochForBlockQuery(baseOptions: Apollo.QueryHookOptions<ExplorerEpochForBlockQuery, ExplorerEpochForBlockQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<ExplorerEpochForBlockQuery, ExplorerEpochForBlockQueryVariables>(ExplorerEpochForBlockDocument, options);
}
export function useExplorerEpochForBlockLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerEpochForBlockQuery, ExplorerEpochForBlockQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<ExplorerEpochForBlockQuery, ExplorerEpochForBlockQueryVariables>(ExplorerEpochForBlockDocument, options);
}
export type ExplorerEpochForBlockQueryHookResult = ReturnType<typeof useExplorerEpochForBlockQuery>;
export type ExplorerEpochForBlockLazyQueryHookResult = ReturnType<typeof useExplorerEpochForBlockLazyQuery>;
export type ExplorerEpochForBlockQueryResult = Apollo.QueryResult<ExplorerEpochForBlockQuery, ExplorerEpochForBlockQueryVariables>;
@@ -4,56 +4,17 @@ import { Link } from 'react-router-dom';
import type { ComponentProps } from 'react';
import Hash from '../hash';
import { useExplorerEpochForBlockQuery } from './__generated__/EpochByBlock';
import { t } from '@vegaprotocol/i18n';
export type BlockLinkProps = Partial<ComponentProps<typeof Link>> & {
height: string;
showEpoch?: boolean;
};
const BlockLink = ({ height, showEpoch = false, ...props }: BlockLinkProps) => {
const BlockLink = ({ height, ...props }: BlockLinkProps) => {
return (
<>
<Link className="underline" {...props} to={`/${Routes.BLOCKS}/${height}`}>
<Hash text={height} />
</Link>
{showEpoch && <EpochForBlock block={height} />}
</>
<Link className="underline" {...props} to={`/${Routes.BLOCKS}/${height}`}>
<Hash text={height} />
</Link>
);
};
export function EpochForBlock(props: { block: string }) {
const { error, data, loading } = useExplorerEpochForBlockQuery({
errorPolicy: 'ignore',
variables: { block: props.block },
});
// NOTE: 0.73.x & <0.74.2 can error showing epoch, so for now we hide loading
// or error states and only display if we get usable data
if (error || loading || !data) {
return null;
}
return (
<span className="ml-2" title={t('Epoch')}>
<EpochSymbol />
{data.epoch.id}
</span>
);
}
export const EPOCH_SYMBOL = 'ⓔ';
export function EpochSymbol() {
return (
<em
title={t('Epoch')}
className="mr-1 cursor-default text-xl leading-none align-text-bottom not-italic"
>
{EPOCH_SYMBOL}
</em>
);
}
export default BlockLink;
@@ -1,16 +0,0 @@
import { render, screen } from '@testing-library/react';
import GovernanceLink from './governance-link';
describe('GovernanceLink', () => {
it('renders the link with the correct text', () => {
render(<GovernanceLink text="Governance internet website" />);
const linkElement = screen.getByText('Governance internet website');
expect(linkElement).toBeInTheDocument();
});
it('renders the link with the correct href and sensible default text', () => {
render(<GovernanceLink />);
const linkElement = screen.getByText('Governance');
expect(linkElement).toBeInTheDocument();
});
});
@@ -1,18 +0,0 @@
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { ENV } from '../../../config/env';
import { t } from '@vegaprotocol/i18n';
export type GovernanceLinkProps = {
text?: string;
};
/**
* Just a link to the governance page, with optional text
*/
const GovernanceLink = ({ text = t('Governance') }: GovernanceLinkProps) => {
const base = ENV.dataSources.governanceUrl;
return <ExternalLink href={base}>{text}</ExternalLink>;
};
export default GovernanceLink;
@@ -10,8 +10,6 @@ import { ChainResponseCode } from '../chain-response-code/chain-reponse.code';
import { TxDataView } from '../../tx-data-view';
import Hash from '../../../links/hash';
import { Signature } from '../../../signature/signature';
import { useExplorerEpochForBlockQuery } from '../../../links/block-link/__generated__/EpochByBlock';
import EpochOverview from '../../../epoch-overview/epoch';
interface TxDetailsSharedProps {
txData: BlockExplorerTransactionResult | undefined;
@@ -46,11 +44,6 @@ export const TxDetailsShared = ({
blockData,
hideTypeRow = false,
}: TxDetailsSharedProps) => {
const { data } = useExplorerEpochForBlockQuery({
errorPolicy: 'ignore',
variables: { block: txData?.block.toString() || '' },
});
if (!txData) {
return <>{t('Awaiting Block Explorer transaction details')}</>;
}
@@ -81,7 +74,7 @@ export const TxDetailsShared = ({
<TableRow modifier="bordered">
<TableCell {...sharedHeaderProps}>{t('Block')}</TableCell>
<TableCell>
<BlockLink height={height} showEpoch={false} />
<BlockLink height={height} />
</TableCell>
</TableRow>
<TableRow modifier="bordered">
@@ -90,7 +83,6 @@ export const TxDetailsShared = ({
<Signature signature={txData.signature} />
</TableCell>
</TableRow>
<TableRow modifier="bordered">
<TableCell {...sharedHeaderProps}>{t('Time')}</TableCell>
<TableCell>
@@ -108,14 +100,6 @@ export const TxDetailsShared = ({
)}
</TableCell>
</TableRow>
{data && data.epoch && (
<TableRow modifier="bordered">
<TableCell scope="row">{t('Epoch')}</TableCell>
<TableCell modifier="bordered">
<EpochOverview id={data.epoch.id} icon={false} />
</TableCell>
</TableRow>
)}
<TableRow modifier="bordered">
<TableCell {...sharedHeaderProps}>{t('Response code')}</TableCell>
<TableCell>
@@ -113,16 +113,13 @@ export const TxDetailsTransfer = ({
/**
* Gets a string description of this transfer
* @param tx A full transfer
* @param txData A full transfer
* @returns string Transfer label
*/
export function getTypeLabelForTransfer(tx: Transfer) {
if (tx.to === SPECIAL_CASE_NETWORK || tx.to === SPECIAL_CASE_NETWORK_ID) {
if (tx.toAccountType === 'ACCOUNT_TYPE_NETWORK_TREASURY') {
return 'Treasury transfer';
}
if (tx.recurring && tx.recurring.dispatchStrategy) {
return 'Reward transfer';
return 'Reward top up transfer';
}
// Else: we don't know that it's a reward transfer, so let's not guess
} else if (tx.recurring) {
@@ -2,7 +2,6 @@ import { t } from '@vegaprotocol/i18n';
import type { components } from '../../../types/explorer';
import { VoteIcon } from '../vote-icon/vote-icon';
import { ExternalChainIcon } from '../links/external-explorer-link/external-chain-icon';
import { getTypeLabelForTransfer } from './details/tx-transfer';
interface TxOrderTypeProps {
orderType: string;
@@ -96,7 +95,7 @@ export function getLabelForOrderType(
/**
* Given a proposal, will return a specific label
* @param proposal
* @param chainEvent
* @returns
*/
export function getLabelForProposal(
@@ -143,36 +142,6 @@ export function getLabelForProposal(
}
}
type label = {
type: string;
colours: string;
};
export function getLabelForTransfer(
transfer: components['schemas']['commandsv1Transfer']
): label {
const type = getTypeLabelForTransfer(transfer);
if (transfer.toAccountType === 'ACCOUNT_TYPE_NETWORK_TREASURY') {
return {
type,
colours:
'text-vega-green dark:text-green bg-vega-dark-150 dark:bg-vega-dark-250',
};
} else if (transfer.recurring) {
return {
type,
colours:
'text-vega-yellow dark:text-yellow bg-vega-dark-150 dark:bg-vega-dark-250',
};
}
return {
type,
colours:
'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-250',
};
}
/**
* Given a chain event, will try to provide a more useful label
* @param chainEvent
@@ -256,10 +225,9 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
if (type === 'Chain Event' && !!command?.chainEvent) {
type = getLabelForChainEvent(command.chainEvent);
colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink';
} else if (type === 'Transfer Funds' && command?.transfer) {
const res = getLabelForTransfer(command.transfer);
type = res.type;
colours = res.colours;
} else if (type === 'Validator Heartbeat') {
colours =
'text-white dark-text-white bg-vega-light-200 dark:bg-vega-dark-100';
} else if (type === 'Proposal' || type === 'Governance Proposal') {
if (command && !!command.proposalSubmission) {
type = getLabelForProposal(command.proposalSubmission);
@@ -16,8 +16,6 @@ import { useBlockInfo } from '@vegaprotocol/tendermint';
import { NodeLink } from '../../../components/links';
import { useDocumentTitle } from '../../../hooks/use-document-title';
import EmptyList from '../../../components/empty-list/empty-list';
import { useExplorerEpochForBlockQuery } from '../../../components/links/block-link/__generated__/EpochByBlock';
import EpochOverview from '../../../components/epoch-overview/epoch';
type Params = { block: string };
@@ -28,11 +26,6 @@ const Block = () => {
state: { data: blockData, loading, error },
} = useBlockInfo(Number(block));
const { data } = useExplorerEpochForBlockQuery({
errorPolicy: 'ignore',
variables: { block: block?.toString() || '' },
});
return (
<section>
<RouteTitle data-testid="block-header">{t(`BLOCK ${block}`)}</RouteTitle>
@@ -82,7 +75,6 @@ const Block = () => {
<code>{blockData.result.block.header.consensus_hash}</code>
</TableCell>
</TableRow>
<TableRow modifier="bordered">
<TableHeader scope="row">Mined by</TableHeader>
<TableCell modifier="bordered">
@@ -105,14 +97,6 @@ const Block = () => {
)}
</TableCell>
</TableRow>
{data && data.epoch && (
<TableRow modifier="bordered">
<TableCell scope="row">{t('Epoch')}</TableCell>
<TableCell modifier="bordered">
<EpochOverview id={data.epoch.id} icon={false} />
</TableCell>
</TableRow>
)}
<TableRow modifier="bordered">
<TableHeader scope="row">Transactions</TableHeader>
<TableCell modifier="bordered">
@@ -33,10 +33,7 @@ export const NetworkAccountsTable = () => {
return (
<section className="md:flex md:flex-row flex-wrap">
{c.map((a) => (
<div
className="basis-1/2 md:basis-1/4"
key={`${a.assetId}-${a.balance}`}
>
<div className="basis-1/2 md:basis-1/4">
<div className="bg-white rounded overflow-hidden shadow-lg dark:bg-black dark:border-slate-500 dark:border">
<div className="text-center p-6 bg-gray-100 dark:bg-slate-900 border-b dark:border-slate-500">
<p className="flex justify-center">
@@ -16,21 +16,19 @@ import type { DeepPartial } from '@apollo/client/utilities';
describe('typeLabel', () => {
it('should return "Transfer" for "OneOffTransfer" kind', () => {
expect(typeLabel('OneOffTransfer')).toBe('Transfer - one time');
expect(typeLabel('OneOffTransfer')).toBe('Transfer');
});
it('should return "Transfer" for "RecurringTransfer" kind', () => {
expect(typeLabel('RecurringTransfer')).toBe('Transfer - repeating');
expect(typeLabel('RecurringTransfer')).toBe('Transfer');
});
it('should return "Governance" for "OneOffGovernanceTransfer" kind', () => {
expect(typeLabel('OneOffGovernanceTransfer')).toBe('Governance - one time');
expect(typeLabel('OneOffGovernanceTransfer')).toBe('Governance');
});
it('should return "Governance" for "RecurringGovernanceTransfer" kind', () => {
expect(typeLabel('RecurringGovernanceTransfer')).toBe(
'Governance - repeating'
);
expect(typeLabel('RecurringGovernanceTransfer')).toBe('Governance');
});
it('should return "Unknown" for unknown kind', () => {
@@ -258,7 +256,7 @@ describe('NetworkTransfersTable', () => {
expect(screen.getByTestId('from-account').textContent).toEqual('Treasury');
expect(screen.getByTestId('to-account').textContent).toEqual('7100…97a0');
expect(screen.getByTestId('transfer-kind').textContent).toEqual(
'Governance - one time'
'Governance'
);
});
});
@@ -12,7 +12,6 @@ import { t } from '@vegaprotocol/i18n';
import { IconNames } from '@blueprintjs/icons';
import { useMemo } from 'react';
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import ProposalLink from '../../../components/links/proposal-link/proposal-link';
export const colours = {
INCOMING: '!fill-vega-green-600 text-vega-green-600 mr-2',
@@ -51,24 +50,14 @@ export function getToAccountTypeLabel(type?: AccountType): string {
}
}
export function isGovernanceTransfer(kind?: string): boolean {
if (kind && kind.includes('Governance')) {
return true;
}
return false;
}
export function typeLabel(kind?: string): string {
switch (kind) {
case 'OneOffTransfer':
return t('Transfer - one time');
case 'RecurringTransfer':
return t('Transfer - repeating');
return t('Transfer');
case 'OneOffGovernanceTransfer':
return t('Governance - one time');
case 'RecurringGovernanceTransfer':
return t('Governance - repeating');
return t('Governance');
default:
return t('Unknown');
}
@@ -250,11 +239,6 @@ export const NetworkTransfersTable = () => {
>
{a && typeLabel(a.kind.__typename)}
</span>
{isGovernanceTransfer(a?.kind.__typename) && a?.id && (
<span className="ml-4">
<ProposalLink id={a?.id} text="View" />
</span>
)}
</td>
</tr>
);
@@ -4,7 +4,6 @@ import { t } from '@vegaprotocol/i18n';
import { RouteTitle } from '../../components/route-title';
import { NetworkAccountsTable } from './components/network-accounts-table';
import { NetworkTransfersTable } from './components/network-transfers-table';
import GovernanceLink from '../../components/links/governance-link/governance-link';
export type NonZeroAccount = {
assetId: string;
@@ -17,33 +16,7 @@ export const NetworkTreasury = () => {
return (
<section>
<RouteTitle data-testid="block-header">{t(`Treasury`)}</RouteTitle>
<details className="w-full md:w-3/5 cursor-pointer shadow-lg p-5 dark:border-l-2 dark:border-vega-green">
<summary>{t('About the Network Treasury')}</summary>
<section className="mt-4 b-1 border-grey">
<p className="mb-2">
The network treasury can hold funds from any active settlement asset
on the network. It is funded periodically by transfers from Gobalsky
as part of the Community Adoption Fund (CAF), but in future may
receive funds from any sources.
</p>
<p className="mb-2">
Funds in the network treasury can be used by creating governance
initiated transfers via{' '}
<GovernanceLink text={t('community governance')} />. These transfers
can be initiated by anyone and be used to fund reward pools, or can
be used to fund other activities the{' '}
<abbr className="decoration-dotted" title="Community Adoption Fund">
CAF
</abbr>{' '}
is exploring.
</p>
<p>
This page shows details of the balances in the treasury, pending
transfers, and historic transfer movements to and from the treasury.
</p>
</section>
</details>
<div className="mt-6">
<div>
<NetworkAccountsTable />
</div>
<div className="mt-5">
@@ -34,6 +34,12 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
cy.connectPublicKey(vegaWalletPubKey);
});
it('Able to connect public key using url', function () {
cy.getByTestId('exit-view').click();
cy.visit(`/?address=${vegaWalletPubKey}`);
verifyConnectedToPubKey();
});
it.skip('Able to connect public key via wallet and view assets in wallet', function () {
verifyConnectedToPubKey();
cy.getByTestId('currency-title', { timeout: 10000 })
+2 -1
View File
@@ -14,6 +14,7 @@ NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/m
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
@@ -23,7 +24,7 @@ NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
#Test configuration variables
CYPRESS_FAIRGROUND=false
+2 -1
View File
@@ -15,11 +15,12 @@ NX_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit suppl
NX_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
NX_VEGA_REST_URL=http://localhost:3008/api/v2/
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
+2 -1
View File
@@ -8,13 +8,14 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_VEGA_EXPLORER_URL=#
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_REST_URL=https://api.n00.devnet1.vega.xyz/api/v2/
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
+1
View File
@@ -10,6 +10,7 @@ NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_REST_URL=https://api.vega.community/api/v2/
+1
View File
@@ -9,6 +9,7 @@ NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-mirror-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_REST_URL=https://api.mainnet-mirror.vega.rocks/api/v2/
+2 -1
View File
@@ -5,6 +5,7 @@ NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","STAGNET1":"https:
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
@@ -12,7 +13,7 @@ NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/m
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
+2 -1
View File
@@ -9,6 +9,7 @@ NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/
@@ -17,7 +18,7 @@ NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/m
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
+1 -1
View File
@@ -14,7 +14,7 @@ NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.
+16 -2
View File
@@ -1,7 +1,7 @@
import * as Sentry from '@sentry/react';
import { toBigNum } from '@vegaprotocol/utils';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet, useEagerConnect } from '@vegaprotocol/wallet-react';
import { useVegaWallet, useEagerConnect } from '@vegaprotocol/wallet';
import { useFeatureFlags, useEnvironment } from '@vegaprotocol/environment';
import { useWeb3React } from '@web3-react/core';
import React, { Suspense } from 'react';
@@ -15,6 +15,20 @@ import {
} from './contexts/app-state/app-state-context';
import { useContracts } from './contexts/contracts/contracts-context';
import { useRefreshAssociatedBalances } from './hooks/use-refresh-associated-balances';
import { useConnectors } from './lib/vega-connectors';
import { useSearchParams } from 'react-router-dom';
const useVegaWalletEagerConnect = () => {
const connectors = useConnectors();
const vegaConnecting = useEagerConnect(connectors);
const { pubKey, connect } = useVegaWallet();
const [searchParams] = useSearchParams();
const [query] = React.useState(searchParams.get('address'));
if (query && !pubKey) {
connect(connectors.view);
}
return vegaConnecting;
};
export const AppLoader = ({ children }: { children: React.ReactElement }) => {
const featureFlags = useFeatureFlags((state) => state.flags);
@@ -26,7 +40,7 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
const { token, staking, vesting } = useContracts();
const setAssociatedBalances = useRefreshAssociatedBalances();
const [balancesLoaded, setBalancesLoaded] = React.useState(false);
const vegaConnecting = useEagerConnect();
const vegaConnecting = useVegaWalletEagerConnect();
const loaded = balancesLoaded && !vegaConnecting;
+141 -31
View File
@@ -1,6 +1,7 @@
import './i18n';
import React, { useEffect } from 'react';
import * as Sentry from '@sentry/react';
import { BrowserRouter as Router, useLocation } from 'react-router-dom';
import { AppLoader } from './app-loader';
import { NetworkInfo } from '@vegaprotocol/network-info';
@@ -25,7 +26,7 @@ import {
} from '@vegaprotocol/web3';
import { Web3Provider } from '@vegaprotocol/web3';
import { VegaWalletDialogs } from './components/vega-wallet-dialogs';
import { WalletProvider } from '@vegaprotocol/wallet-react';
import { VegaWalletProvider, useChainId } from '@vegaprotocol/wallet';
import {
useVegaTransactionManager,
useVegaTransactionUpdater,
@@ -35,21 +36,26 @@ import { useEthereumConfig } from '@vegaprotocol/web3';
import {
useEnvironment,
NetworkLoader,
useInitializeEnv,
NodeGuard,
NodeSwitcherDialog,
useNodeSwitcherStore,
DocsLinks,
NodeFailure,
AppLoader as Loader,
useInitializeEnv,
} from '@vegaprotocol/environment';
import { ENV } from './config';
import type { InMemoryCacheConfig } from '@apollo/client';
import { CreateWithdrawalDialog } from '@vegaprotocol/withdraws';
import { SplashLoader } from './components/splash-loader';
import { ToastsManager } from './toasts-manager';
import { TelemetryDialog } from './components/telemetry-dialog/telemetry-dialog';
import {
TelemetryDialog,
TELEMETRY_ON,
} from './components/telemetry-dialog/telemetry-dialog';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
import { useTranslation } from 'react-i18next';
import { useSentryInit } from './hooks/use-sentry-init';
import { useVegaWalletConfig } from './hooks/use-vega-wallet-config';
import { isPartyNotFoundError } from './lib/party';
const cache: InMemoryCacheConfig = {
typePolicies: {
@@ -98,12 +104,32 @@ const Web3Container = ({
/** Ethereum provider url */
providerUrl: string;
}) => {
const InitializeHandlers = () => {
useVegaTransactionManager();
useVegaTransactionUpdater();
useEthTransactionManager();
useEthTransactionUpdater();
useEthWithdrawApprovalsManager();
return null;
};
const [connectors, initializeConnectors] = useWeb3ConnectStore((store) => [
store.connectors,
store.initialize,
]);
const { ETHEREUM_PROVIDER_URL, ETH_LOCAL_PROVIDER_URL, ETH_WALLET_MNEMONIC } =
useEnvironment();
const {
ETHEREUM_PROVIDER_URL,
ETH_LOCAL_PROVIDER_URL,
ETH_WALLET_MNEMONIC,
VEGA_ENV,
VEGA_URL,
VEGA_EXPLORER_URL,
CHROME_EXTENSION_URL,
MOZILLA_EXTENSION_URL,
VEGA_WALLET_URL,
} = useEnvironment();
const vegaChainId = useChainId(VEGA_URL);
useEffect(() => {
if (chainId) {
@@ -124,31 +150,50 @@ const Web3Container = ({
ETH_LOCAL_PROVIDER_URL,
ETH_WALLET_MNEMONIC,
]);
const sideBar = React.useMemo(() => {
return [<EthWallet />, <VegaWallet />];
}, []);
const vegaWalletConfig = useVegaWalletConfig();
if (!vegaWalletConfig || connectors.length === 0) {
if (connectors.length === 0) {
// Prevent loading when the connectors are not initialized
return <SplashLoader />;
}
if (
!VEGA_URL ||
!VEGA_WALLET_URL ||
!VEGA_EXPLORER_URL ||
!DocsLinks ||
!CHROME_EXTENSION_URL ||
!MOZILLA_EXTENSION_URL ||
!vegaChainId
) {
return null;
}
return (
<Web3Provider connectors={connectors}>
<Web3Connector connectors={connectors} chainId={Number(chainId)}>
<WalletProvider config={vegaWalletConfig}>
<VegaWalletProvider
config={{
network: VEGA_ENV,
vegaUrl: VEGA_URL,
chainId: vegaChainId,
vegaWalletServiceUrl: VEGA_WALLET_URL,
links: {
explorer: VEGA_EXPLORER_URL,
concepts: DocsLinks?.VEGA_WALLET_CONCEPTS_URL,
chromeExtensionUrl: CHROME_EXTENSION_URL,
mozillaExtensionUrl: MOZILLA_EXTENSION_URL,
},
}}
>
<ContractsProvider>
<AppLoader>
<BalanceManager>
<>
<AppLayout>
<TemplateSidebar
sidebar={
<>
<EthWallet />
<VegaWallet />
</>
}
>
<TemplateSidebar sidebar={sideBar}>
<AppRouter />
</TemplateSidebar>
<footer className="p-4 break-all border-t border-neutral-700">
@@ -166,7 +211,7 @@ const Web3Container = ({
</BalanceManager>
</AppLoader>
</ContractsProvider>
</WalletProvider>
</VegaWalletProvider>
</Web3Connector>
</Web3Provider>
);
@@ -186,9 +231,20 @@ const ScrollToTop = () => {
return null;
};
const removeQueryParams = (url: string) => {
return url.split('?')[0];
};
const AppContainer = () => {
const { config, loading, error } = useEthereumConfig();
const { VEGA_URL, ETHEREUM_PROVIDER_URL } = useEnvironment();
const {
VEGA_ENV,
VEGA_URL,
GIT_COMMIT_HASH,
GIT_BRANCH,
ETHEREUM_PROVIDER_URL,
} = useEnvironment();
const [telemetryOn] = useLocalStorage(TELEMETRY_ON);
const { t } = useTranslation();
const [nodeSwitcherOpen, setNodeSwitcher] = useNodeSwitcherStore((store) => [
store.dialogOpen,
@@ -198,7 +254,70 @@ const AppContainer = () => {
// Hacky skip all the loading & web3 init for geo restricted users
const isRestricted = document?.location?.pathname?.includes('/restricted');
useSentryInit();
useEffect(() => {
if (ENV.dsn && telemetryOn === 'true') {
Sentry.init({
dsn: ENV.dsn,
tracesSampleRate: 0.1,
enabled: true,
environment: VEGA_ENV,
release: GIT_COMMIT_HASH,
beforeSend(event, hint) {
const error = hint?.originalException;
const errorIsString = typeof error === 'string';
const errorIsObject = error instanceof Error;
const requestUrl = event.request?.url;
const transaction = event.transaction;
if (
(errorIsString && isPartyNotFoundError({ message: error })) ||
(errorIsObject && isPartyNotFoundError(error))
) {
// This error is caused by a pubkey making an API request before
// it has interacted with the chain. This isn't needed in Sentry.
return null;
}
const updatedRequest =
requestUrl && requestUrl.includes('/claim?')
? { ...event.request, url: removeQueryParams(requestUrl) }
: event.request;
const updatedTransaction =
transaction && transaction.includes('/claim?')
? removeQueryParams(transaction)
: transaction;
const updatedBreadcrumbs = event.breadcrumbs?.map((breadcrumb) => {
if (
breadcrumb.type === 'navigation' &&
breadcrumb.data?.to?.includes('/claim?')
) {
return {
...breadcrumb,
data: {
...breadcrumb.data,
to: removeQueryParams(breadcrumb.data.to),
},
};
}
return breadcrumb;
});
return {
...event,
request: updatedRequest,
transaction: updatedTransaction,
breadcrumbs: updatedBreadcrumbs ?? event.breadcrumbs,
};
},
});
Sentry.setTag('branch', GIT_BRANCH);
Sentry.setTag('commit', GIT_COMMIT_HASH);
} else {
Sentry.close();
}
}, [GIT_COMMIT_HASH, GIT_BRANCH, VEGA_ENV, telemetryOn]);
if (isRestricted) {
return (
@@ -240,15 +359,6 @@ const AppContainer = () => {
);
};
const InitializeHandlers = () => {
useVegaTransactionManager();
useVegaTransactionUpdater();
useEthTransactionManager();
useEthTransactionUpdater();
useEthWithdrawApprovalsManager();
return null;
};
function App() {
useInitializeEnv();
@@ -7,7 +7,7 @@ import { useGetAssociationBreakdown } from '../../hooks/use-get-association-brea
import { useGetUserBalances } from '../../hooks/use-get-user-balances';
import { useBalances } from '../../lib/balances/balances-store';
import type { ReactElement } from 'react';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useListenForStakingEvents as useListenForAssociationEvents } from '../../hooks/use-listen-for-staking-events';
import { useTranches } from '../../lib/tranches/tranches-store';
import { useUserTrancheBalances } from '../../routes/redemption/hooks';
@@ -15,16 +15,19 @@ export const CollapsibleToggle = ({
dataTestId,
children,
}: CollapsibleToggleProps) => {
const classes = classnames('transition-transform ease-in-out duration-300', {
'rotate-180': toggleState,
});
const classes = classnames(
'mb-4 transition-transform ease-in-out duration-300',
{
'rotate-180': toggleState,
}
);
return (
<button
onClick={() => setToggleState(!toggleState)}
data-testid={dataTestId}
>
<div className="flex items-baseline gap-3">
<div className="flex items-center gap-3">
{children}
<div className={classes} data-testid="toggle-icon-wrapper">
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={20} />
@@ -1,13 +1,18 @@
import { Button } from '@vegaprotocol/ui-toolkit';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useDialogStore } from '@vegaprotocol/wallet-react';
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
export const ConnectToVega = () => {
const { t } = useTranslation();
const openVegaWalletDialog = useDialogStore((store) => store.open);
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
return (
<Button
onClick={openVegaWalletDialog}
onClick={() => {
openVegaWalletDialog();
}}
data-testid="connect-to-vega-wallet-btn"
variant="primary"
>
@@ -1,5 +1,5 @@
import classNames from 'classnames';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import type { ReactNode } from 'react';
import { AnnouncementBanner } from '@vegaprotocol/announcements';
import { Nav } from '../nav';
@@ -1,8 +1,8 @@
import { Children, type ReactNode } from 'react';
import React from 'react';
export interface TemplateSidebarProps {
children: ReactNode;
sidebar: ReactNode;
children: React.ReactNode;
sidebar: React.ReactNode[];
}
export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
@@ -12,9 +12,9 @@ export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
{children}
</main>
<aside className="col-start-2 row-start-1 row-span-2 hidden lg:block p-4 bg-banner bg-contain border-l border-neutral-700">
{Children.map(sidebar, (child, i) => (
{sidebar.map((Component, i) => (
<section className="mb-4 last:mb-0" key={i}>
{child}
{Component}
</section>
))}
</aside>
@@ -1,5 +1,5 @@
import { Button } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet, useDialogStore } from '@vegaprotocol/wallet-react';
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import React from 'react';
import { useTranslation } from 'react-i18next';
@@ -10,7 +10,9 @@ interface VegaWalletContainerProps {
export const VegaWalletContainer = ({ children }: VegaWalletContainerProps) => {
const { t } = useTranslation();
const { pubKey } = useVegaWallet();
const openVegaWalletDialog = useDialogStore((store) => store.open);
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
if (!pubKey) {
return (
@@ -9,7 +9,7 @@ import Routes from '../../routes/routes';
export const RiskMessage = () => {
return (
<>
<div className="bg-vega-light-100 dark:bg-vega-dark-100 p-6">
<div className="bg-vega-light-100 dark:bg-vega-dark-100 p-6 mb-6">
<ul className="list-[square] ml-4">
<li>
{t(
@@ -23,7 +23,7 @@ export const RiskMessage = () => {
</li>
</ul>
</div>
<p>
<p className="mb-8">
{t(
'By using the Vega Governance App, you acknowledge that you have read and understood the'
)}{' '}
@@ -1,39 +1,25 @@
import {
ConnectDialogWithRiskAck,
useDialogStore,
} from '@vegaprotocol/wallet-react';
VegaConnectDialog,
VegaManageDialog,
ViewAsDialog,
} from '@vegaprotocol/wallet';
import {
AppStateActionType,
useAppState,
} from '../../contexts/app-state/app-state-context';
import { useConnectors } from '../../lib/vega-connectors';
import { RiskMessage } from './risk-message';
import { VegaManageDialog } from '../manage-dialog';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
import { Networks, useEnvironment } from '@vegaprotocol/environment';
export const VegaWalletDialogs = () => {
const { VEGA_ENV } = useEnvironment();
const { appState, appDispatch } = useAppState();
const [riskAccepted, setRiskAccepted] = useLocalStorage(
'vega_wallet_risk_accepted'
);
const vegaWalletDialogOpen = useDialogStore((store) => store.isOpen);
const setVegaWalletDialog = useDialogStore((store) => store.set);
const connectors = useConnectors();
return (
<>
<ConnectDialogWithRiskAck
open={vegaWalletDialogOpen}
onChange={setVegaWalletDialog}
riskAccepted={
VEGA_ENV === Networks.TESTNET ? riskAccepted === 'true' : true
}
riskAckContent={<RiskMessage />}
onRiskAccepted={() => setRiskAccepted('true')}
onRiskRejected={() => {
setRiskAccepted('false');
setVegaWalletDialog(false);
}}
<VegaConnectDialog
connectors={connectors}
riskMessage={<RiskMessage />}
/>
<VegaManageDialog
dialogOpen={appState.vegaWalletManageOverlay}
setDialogOpen={(open) =>
@@ -43,6 +29,8 @@ export const VegaWalletDialogs = () => {
})
}
/>
<ViewAsDialog connector={connectors.view} />
</>
);
};
@@ -4,13 +4,14 @@ import keyBy from 'lodash/keyBy';
import uniq from 'lodash/uniq';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ENV } from '../../config';
import noIcon from '../../images/token-no-icon.png';
import vegaBlack from '../../images/vega_black.png';
import vegaVesting from '../../images/vega_vesting.png';
import { BigNumber } from '../../lib/bignumber';
import { type WalletCardAssetProps } from '../wallet-card';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useContracts } from '../../contexts/contracts/contracts-context';
import * as Schema from '@vegaprotocol/types';
import {
@@ -36,6 +37,7 @@ export const usePollForDelegations = () => {
const { t } = useTranslation();
const { pubKey } = useVegaWallet();
const client = useApolloClient();
const { delegationsPagination } = ENV;
const [delegations, setDelegations] = React.useState<
WalletDelegationFieldsFragment[]
>([]);
@@ -66,9 +68,11 @@ export const usePollForDelegations = () => {
query: DelegationsDocument,
variables: {
partyId: pubKey,
delegationsPagination: {
first: 50,
},
delegationsPagination: delegationsPagination
? {
first: Number(delegationsPagination),
}
: undefined,
},
fetchPolicy: 'network-only',
})
@@ -232,14 +236,14 @@ export const usePollForDelegations = () => {
// will just continue to fail
clearInterval(interval);
});
}, 20000);
}, 1000);
}
return () => {
clearInterval(interval);
mounted = false;
};
}, [client, decimals, pubKey, t, vegaToken.address]);
}, [delegationsPagination, client, decimals, pubKey, t, vegaToken.address]);
return { delegations, currentStakeAvailable, delegatedNodes, accounts };
};
@@ -1,11 +1,11 @@
import { ButtonLink, Link } from '@vegaprotocol/ui-toolkit';
import { useTranslation } from 'react-i18next';
import { ExternalLinks } from '@vegaprotocol/environment';
import { useConnect } from '@vegaprotocol/wallet-react';
import { useViewAsDialog } from '@vegaprotocol/wallet';
export const VegaWalletPrompt = () => {
const { t } = useTranslation();
const { connect } = useConnect();
const setViewAsDialog = useViewAsDialog((state) => state.setOpen);
return (
<>
<h3 className="mt-4 mb-2">{t('getWallet')}</h3>
@@ -16,7 +16,7 @@ export const VegaWalletPrompt = () => {
<ButtonLink
className="text-neutral-500"
data-testid="view-as-user"
onClick={() => connect('viewParty')}
onClick={() => setViewAsDialog(true)}
>
{t('viewAsParty')}
</ButtonLink>
@@ -25,7 +25,7 @@ import {
} from '../wallet-card';
import { VegaWalletPrompt } from './vega-wallet-prompt';
import { usePollForDelegations } from './hooks';
import { useVegaWallet, useDialogStore } from '@vegaprotocol/wallet-react';
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import { Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
import { toBigNum } from '@vegaprotocol/utils';
import { usePendingBalancesStore } from '../../hooks/use-pending-balances-manager';
@@ -34,17 +34,16 @@ import omit from 'lodash/omit';
export const VegaWallet = () => {
const { t } = useTranslation();
const { status, pubKey, pubKeys } = useVegaWallet();
const { pubKey, pubKeys } = useVegaWallet();
const pubKeyObj = useMemo(() => {
return pubKeys?.find((pk) => pk.publicKey === pubKey);
}, [pubKey, pubKeys]);
const child =
status === 'connected' ? (
<VegaWalletConnected vegaKeys={pubKeys.map((pk) => pk.publicKey)} />
) : (
<VegaWalletNotConnected />
);
const child = !pubKeys ? (
<VegaWalletNotConnected />
) : (
<VegaWalletConnected vegaKeys={pubKeys.map((pk) => pk.publicKey)} />
);
return (
<section className="vega-wallet" data-testid="vega-wallet">
@@ -76,7 +75,9 @@ export const VegaWallet = () => {
const VegaWalletNotConnected = () => {
const { t } = useTranslation();
const openVegaWalletDialog = useDialogStore((store) => store.open);
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
return (
<>
<Button
+1
View File
@@ -65,6 +65,7 @@ export const ENV = {
docsUrl: windowOrDefault('NX_VEGA_DOCS_URL'),
ethWalletMnemonic: windowOrDefault('NX_ETH_WALLET_MNEMONIC'),
localProviderUrl: windowOrDefault('NX_LOCAL_PROVIDER_URL'),
delegationsPagination: windowOrDefault('NX_DELEGATIONS_PAGINATION'),
rest: windowOrDefault('NX_VEGA_REST_URL'),
addresses:
ContractAddresses[(envName === 'local' ? 'CUSTOM' : envName) as Networks],
@@ -7,7 +7,7 @@ import { useWeb3React } from '@web3-react/core';
export const useListenForStakingEvents = (
contract: Contract | undefined,
vegaPublicKey: string | undefined,
vegaPublicKey: string | null,
numberOfConfirmations: number
) => {
const { account } = useWeb3React();
@@ -1,6 +1,6 @@
import * as Sentry from '@sentry/react';
import { toBigNum } from '@vegaprotocol/utils';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useEthereumConfig } from '@vegaprotocol/web3';
import React from 'react';
@@ -1,81 +0,0 @@
import { useEffect } from 'react';
import * as Sentry from '@sentry/react';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
import { TELEMETRY_ON } from '../components/telemetry-dialog/telemetry-dialog';
import { useEnvironment } from '@vegaprotocol/environment';
import { ENV } from '../config';
import { isPartyNotFoundError } from '../lib/party';
export const useSentryInit = () => {
const { VEGA_ENV, GIT_COMMIT_HASH, GIT_BRANCH } = useEnvironment();
const [telemetryOn] = useLocalStorage(TELEMETRY_ON);
useEffect(() => {
if (ENV.dsn && telemetryOn === 'true') {
Sentry.init({
dsn: ENV.dsn,
tracesSampleRate: 0.1,
enabled: true,
environment: VEGA_ENV,
release: GIT_COMMIT_HASH,
beforeSend(event, hint) {
const error = hint?.originalException;
const errorIsString = typeof error === 'string';
const errorIsObject = error instanceof Error;
const requestUrl = event.request?.url;
const transaction = event.transaction;
if (
(errorIsString && isPartyNotFoundError({ message: error })) ||
(errorIsObject && isPartyNotFoundError(error))
) {
// This error is caused by a pubkey making an API request before
// it has interacted with the chain. This isn't needed in Sentry.
return null;
}
const updatedRequest =
requestUrl && requestUrl.includes('/claim?')
? { ...event.request, url: removeQueryParams(requestUrl) }
: event.request;
const updatedTransaction =
transaction && transaction.includes('/claim?')
? removeQueryParams(transaction)
: transaction;
const updatedBreadcrumbs = event.breadcrumbs?.map((breadcrumb) => {
if (
breadcrumb.type === 'navigation' &&
breadcrumb.data?.to?.includes('/claim?')
) {
return {
...breadcrumb,
data: {
...breadcrumb.data,
to: removeQueryParams(breadcrumb.data.to),
},
};
}
return breadcrumb;
});
return {
...event,
request: updatedRequest,
transaction: updatedTransaction,
breadcrumbs: updatedBreadcrumbs ?? event.breadcrumbs,
};
},
});
Sentry.setTag('branch', GIT_BRANCH);
Sentry.setTag('commit', GIT_COMMIT_HASH);
} else {
Sentry.close();
}
}, [GIT_COMMIT_HASH, GIT_BRANCH, VEGA_ENV, telemetryOn]);
};
const removeQueryParams = (url: string) => {
return url.split('?')[0];
};
@@ -1,41 +0,0 @@
import { useMemo } from 'react';
import {
InjectedConnector,
JsonRpcConnector,
SnapConnector,
ViewPartyConnector,
createConfig,
fairground,
stagnet,
mainnet,
} from '@vegaprotocol/wallet';
import { useEnvironment } from '@vegaprotocol/environment';
export const useVegaWalletConfig = () => {
const { VEGA_ENV, VEGA_URL, VEGA_WALLET_URL } = useEnvironment();
return useMemo(() => {
if (!VEGA_ENV || !VEGA_URL || !VEGA_WALLET_URL) return;
const injected = new InjectedConnector();
const jsonRpc = new JsonRpcConnector({
url: VEGA_WALLET_URL,
});
const snap = new SnapConnector({
node: new URL(VEGA_URL).origin,
snapId: 'npm:@vegaprotocol/snap',
version: '1.0.1',
});
const viewParty = new ViewPartyConnector();
const config = createConfig({
chains: [mainnet, fairground, stagnet],
defaultChainId: fairground.id,
connectors: [injected, snap, jsonRpc, viewParty],
});
return config;
}, [VEGA_ENV, VEGA_URL, VEGA_WALLET_URL]);
};
+1 -1
View File
@@ -31,7 +31,7 @@ i18n
load: 'languageOnly',
debug: isInDev,
// have a common namespace used around the full app
ns: ['governance', 'wallet', 'wallet-react'],
ns: ['governance'],
defaultNS: 'governance',
keySeparator: false, // we use content as keys
nsSeparator: false,
@@ -20,7 +20,6 @@ describe('getMultisigStatus', () => {
expect(result).toEqual({
multisigStatus: MultisigStatus.noNodes,
showMultisigStatusError: true,
zeroScoreNodes: [],
});
});
@@ -36,7 +35,6 @@ describe('getMultisigStatus', () => {
expect(result).toEqual({
multisigStatus: MultisigStatus.correct,
showMultisigStatusError: false,
zeroScoreNodes: [],
});
});
@@ -52,22 +50,6 @@ describe('getMultisigStatus', () => {
expect(result).toEqual({
multisigStatus: MultisigStatus.nodeNeedsRemoving,
showMultisigStatusError: true,
zeroScoreNodes: [
{
id: '1',
rewardScore: {
multisigScore: '0',
},
stakedTotal: '1000',
},
{
id: '2',
rewardScore: {
multisigScore: '0',
},
stakedTotal: '1000',
},
],
});
});
@@ -83,15 +65,6 @@ describe('getMultisigStatus', () => {
expect(result).toEqual({
multisigStatus: MultisigStatus.nodeNeedsAdding,
showMultisigStatusError: true,
zeroScoreNodes: [
{
id: '1',
rewardScore: {
multisigScore: '0',
},
stakedTotal: '1000',
},
],
});
});
});
@@ -1,8 +1,5 @@
import { removePaginationWrapper } from '@vegaprotocol/utils';
import type {
PreviousEpochQuery,
ValidatorNodeFragment,
} from '../routes/staking/__generated__/PreviousEpoch';
import type { PreviousEpochQuery } from '../routes/staking/__generated__/PreviousEpoch';
export enum MultisigStatus {
'correct' = 'correct',
@@ -20,15 +17,12 @@ export const getMultisigStatusInfo = (
previousEpochData?.epoch.validatorsConnection?.edges
);
const zeroScore = (node: ValidatorNodeFragment) =>
Number(node.rewardScore?.multisigScore) === 0;
const oneScore = (node: ValidatorNodeFragment) =>
Number(node.rewardScore?.multisigScore) === 1;
const hasZero = allNodesInPreviousEpoch.some(zeroScore);
const hasOne = allNodesInPreviousEpoch.some(oneScore);
const zeroScoreNodes = allNodesInPreviousEpoch.filter(zeroScore);
const hasZero = allNodesInPreviousEpoch.some(
(node) => Number(node?.rewardScore?.multisigScore) === 0
);
const hasOne = allNodesInPreviousEpoch.some(
(node) => Number(node?.rewardScore?.multisigScore) === 1
);
if (hasZero && hasOne) {
// If any individual node has 0 it means that node is missing from the multisig and needs to be added
@@ -44,6 +38,5 @@ export const getMultisigStatusInfo = (
return {
showMultisigStatusError: status !== MultisigStatus.correct,
multisigStatus: status,
zeroScoreNodes,
};
};
@@ -0,0 +1,30 @@
import { useFeatureFlags } from '@vegaprotocol/environment';
import { useMemo } from 'react';
import {
JsonRpcConnector,
ViewConnector,
InjectedConnector,
SnapConnector,
DEFAULT_SNAP_ID,
} from '@vegaprotocol/wallet';
const urlParams = new URLSearchParams(window.location.search);
export const jsonRpc = new JsonRpcConnector();
export const injected = new InjectedConnector();
export const view = new ViewConnector(urlParams.get('address'));
export const snap = new SnapConnector(DEFAULT_SNAP_ID);
export const useConnectors = () => {
const featureFlags = useFeatureFlags((state) => state.flags);
return useMemo(
() => ({
injected,
jsonRpc,
view,
snap: featureFlags.METAMASK_SNAPS ? snap : undefined,
}),
[featureFlags.METAMASK_SNAPS]
);
};
@@ -5,6 +5,7 @@ import {
ProposalState,
VoteValue,
} from '@vegaprotocol/types';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import {
generateNoVotes,
@@ -15,7 +16,9 @@ import { ProposalHeader, NewTransferSummary } from './proposal-header';
import {
lastWeek,
nextWeek,
mockWalletContext,
createUserVoteQueryMock,
networkParamsQueryMock,
} from '../../test-helpers/mocks';
import { BrowserRouter } from 'react-router-dom';
import { VoteState } from '../vote-details/use-user-vote';
@@ -42,12 +45,14 @@ const renderComponent = (
render(
<AppStateProvider>
<BrowserRouter>
<MockedProvider mocks={mocks}>
<ProposalHeader
proposal={proposal}
isListItem={isListItem}
voteState={voteState}
/>
<MockedProvider mocks={[networkParamsQueryMock, ...mocks]}>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposalHeader
proposal={proposal}
isListItem={isListItem}
voteState={voteState}
/>
</VegaWalletContext.Provider>
</MockedProvider>
</BrowserRouter>
</AppStateProvider>
@@ -155,7 +160,7 @@ describe('Proposal header', () => {
screen.queryByTestId('proposal-description')
).not.toBeInTheDocument();
expect(screen.getByTestId('proposal-details')).toHaveTextContent(
/Update to market: MarketId/
'Update to market: MarketId'
);
});
@@ -36,8 +36,8 @@ import { type Proposal, type BatchProposal } from '../../types';
import { type ProposalTermsFieldsFragment } from '../../__generated__/Proposals';
import { differenceInHours, format, formatDistanceToNowStrict } from 'date-fns';
import { DATE_FORMAT_DETAILED } from '../../../../lib/date-formats';
import { getIndicatorStyle } from '../proposal/colours';
import { MarketName } from '../proposal/market-name';
import { Indicator } from '../proposal/indicator';
const ProposalTypeTags = ({
proposal,
@@ -250,7 +250,7 @@ const ProposalDetails = ({
}}
components={{
// @ts-ignore children passed by i18next
lozenge: <Lozenge className="text-xs" />,
lozenge: <Lozenge />,
}}
/>
);
@@ -312,11 +312,8 @@ const ProposalDetails = ({
{proposal.subProposals.map((p, i) => {
if (!p?.terms) return null;
return (
<li
key={i}
className="grid grid-cols-[40px_minmax(0,1fr)] grid-rows-1 gap-3 items-center"
>
<Indicator indicator={i + 1} />
<li key={i} className="flex gap-3 items-center">
<span className={getIndicatorStyle(i + 1)}>{i + 1}</span>
<span>
<div>{renderDetails(p.terms)}</div>
<SubProposalStateText
@@ -18,7 +18,7 @@ export const ProposalJson = ({ proposal }: { proposal?: unknown }) => {
<SubHeading title={t('proposalJson')} />
</CollapsibleToggle>
{showDetails && <SyntaxHighlighter size="smaller" data={proposal} />}
{showDetails && <SyntaxHighlighter data={proposal} />}
</section>
);
};
@@ -143,14 +143,14 @@ export const ProposalMarketChanges = ({
<SubHeading
title={
<>
{t('UpdateToMarket')}: <MarketName marketId={marketId} truncate />
{t('UpdateToMarket')}: <MarketName marketId={marketId} />
</>
}
/>
</CollapsibleToggle>
{showChanges && (
<div className="mb-6 bg-vega-cdark-900 p-2 rounded-lg">
<div className="mb-6">
<JsonDiff left={left as JsonValue} right={right as JsonValue} />
</div>
)}
@@ -16,21 +16,21 @@ const getColour = (indicator: number, max = COLOURS.length) => {
export const getStyle = (indicator: number, max = COLOURS.length) =>
classNames({
'bg-vega-yellow-400 before:bg-vega-yellow-400':
'bg-vega-yellow-400 after:bg-vega-yellow-400':
'yellow' === getColour(indicator, max),
'bg-vega-green-400 before:bg-vega-green-400':
'bg-vega-green-400 after:bg-vega-green-400':
'green' === getColour(indicator, max),
'bg-vega-blue-400 before:bg-vega-blue-400':
'bg-vega-blue-400 after:bg-vega-blue-400':
'blue' === getColour(indicator, max),
'bg-vega-purple-400 before:bg-vega-purple-400':
'bg-vega-purple-400 after:bg-vega-purple-400':
'purple' === getColour(indicator, max),
'bg-vega-pink-400 before:bg-vega-pink-400':
'bg-vega-pink-400 after:bg-vega-pink-400':
'pink' === getColour(indicator, max),
'bg-vega-orange-400 before:bg-vega-orange-400':
'bg-vega-orange-400 after:bg-vega-orange-400':
'orange' === getColour(indicator, max),
'bg-vega-red-400 before:bg-vega-red-400':
'bg-vega-red-400 after:bg-vega-red-400':
'red' === getColour(indicator, max),
'bg-vega-clight-600 before:bg-vega-clight-600':
'bg-vega-clight-600 after:bg-vega-clight-600':
'none' === getColour(indicator, max),
});
@@ -40,7 +40,7 @@ export const getIndicatorStyle = (indicator: number) =>
'text-border-1',
getStyle(indicator),
// Comment below if you want to remove the "chevron"
'relative mr-[11px] z-1',
'before:absolute before:z-0 before:top-1 before:right-[-11px] before:rounded-sm',
"before:w-[22.62px] before:h-[22.62px] before:rotate-45 before:content-['']"
'relative mr-[11px]',
'after:absolute after:z-[-1] after:top-1 after:right-[-11px] after:rounded-sm',
"after:w-[22.62px] after:h-[22.62px] after:rotate-45 after:content-['']"
);
@@ -1,9 +0,0 @@
import { getIndicatorStyle } from './colours';
export const Indicator = ({ indicator }: { indicator: number }) => (
<div className={getIndicatorStyle(indicator)}>
<span className="absolute top-0 left-0 p-1 w-full text-center z-1">
{indicator}
</span>
</div>
);
@@ -1,13 +1,6 @@
import { useMarketInfoQuery } from '@vegaprotocol/markets';
import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
export const MarketName = ({
marketId,
truncate,
}: {
marketId?: string;
truncate?: boolean;
}) => {
export const MarketName = ({ marketId }: { marketId?: string }) => {
const { data } = useMarketInfoQuery({
variables: {
marketId: marketId || '',
@@ -15,7 +8,7 @@ export const MarketName = ({
skip: !marketId,
});
const id = truncate ? truncateMiddle(marketId || '') : marketId;
return <span>{data?.market?.tradableInstrument.instrument.code || id}</span>;
return (
<span>{data?.market?.tradableInstrument.instrument.code || marketId}</span>
);
};
@@ -1,4 +1,3 @@
import { Trans, useTranslation } from 'react-i18next';
import { type ProposalTermsFieldsFragment } from '../../__generated__/Proposals';
import { type Proposal, type BatchProposal } from '../../types';
import { ListAsset } from '../list-asset';
@@ -13,10 +12,8 @@ import {
import { ProposalUpdateBenefitTiers } from '../proposal-update-benefit-tiers';
import { ProposalUpdateMarketState } from '../proposal-update-market-state';
import { ProposalVolumeDiscountProgramDetails } from '../proposal-volume-discount-program-details';
import { getIndicatorStyle } from './colours';
import { type ProposalNode } from './proposal-utils';
import { Lozenge } from '@vegaprotocol/ui-toolkit';
import { Indicator } from './indicator';
import { SubHeading } from '../../../../components/heading';
export const ProposalChangeDetails = ({
proposal,
@@ -29,7 +26,6 @@ export const ProposalChangeDetails = ({
restData: ProposalNode | null;
indicator?: number;
}) => {
const { t } = useTranslation();
let details = null;
switch (terms.change.__typename) {
@@ -112,25 +108,6 @@ export const ProposalChangeDetails = ({
'rewards.activityStreak.benefitTiers'
) {
details = <ProposalUpdateBenefitTiers change={terms.change} />;
} else {
details = (
<div className="mb-4">
<SubHeading title={t(terms.change.__typename as string)} />
<span>
<Trans
i18nKey="Change <lozenge>{{key}}</lozenge> to <lozenge>{{value}}</lozenge>"
values={{
key: terms.change.networkParameter.key,
value: terms.change.networkParameter.value,
}}
components={{
// @ts-ignore children passed by i18next
lozenge: <Lozenge />,
}}
/>
</span>
</div>
);
}
break;
@@ -143,12 +120,10 @@ export const ProposalChangeDetails = ({
}
}
if (indicator != null && details != null) {
if (indicator != null) {
details = (
<div className="grid grid-cols-[40px_minmax(0,1fr)] grid-rows-1 gap-3 mb-3">
<div className="w-10">
<Indicator indicator={indicator} />
</div>
<div className="flex gap-3 mb-3">
<div className={getIndicatorStyle(indicator)}>{indicator}</div>
<div>{details}</div>
</div>
);
@@ -1,12 +1,12 @@
import { MemoryRouter } from 'react-router-dom';
import { MockedProvider } from '@apollo/client/testing';
import { VegaWalletProvider } from '@vegaprotocol/wallet';
import { type VegaWalletConfig } from '@vegaprotocol/wallet';
import { render, screen } from '@testing-library/react';
import { generateProposal } from '../../test-helpers/generate-proposals';
import { Proposal } from './proposal';
import { ProposalState } from '@vegaprotocol/types';
import { type Proposal as IProposal } from '../../types';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { MockedWalletProvider } from '@vegaprotocol/wallet-react/testing';
jest.mock('@vegaprotocol/network-parameters', () => ({
...jest.requireActual('@vegaprotocol/network-parameters'),
@@ -24,44 +24,45 @@ jest.mock('@vegaprotocol/network-parameters', () => ({
error: null,
})),
}));
jest.mock('../proposal-detail-header/proposal-header', () => ({
ProposalHeader: () => <div data-testid="proposal-header"></div>,
}));
jest.mock('../proposal-change-table', () => ({
ProposalChangeTable: () => <div data-testid="proposal-change-table"></div>,
}));
jest.mock('../proposal-json', () => ({
ProposalJson: () => <div data-testid="proposal-json"></div>,
}));
jest.mock('../list-asset', () => ({
ListAsset: () => <div data-testid="proposal-list-asset"></div>,
}));
jest.mock('../list-asset', () => ({
ListAsset: () => <div data-testid="proposal-list-asset"></div>,
}));
jest.mock('../vote-details', () => ({
UserVote: () => <div data-testid="user-vote"></div>,
}));
jest.mock('./proposal-change-details', () => ({
ProposalChangeDetails: () => <div data-testid="proposal-change-details" />,
ProposalChangeDetails: () => (
<div data-testid="proposal-change-details"></div>
),
}));
const vegaWalletConfig: VegaWalletConfig = {
network: 'TESTNET',
vegaUrl: 'https://vega.xyz',
vegaWalletServiceUrl: 'https://wallet.vega.xyz',
links: {
explorer: 'explorer',
concepts: 'concepts',
chromeExtensionUrl: 'chrome',
mozillaExtensionUrl: 'mozilla',
},
chainId: 'VEGA_CHAIN_ID',
};
const renderComponent = (proposal: IProposal) => {
return render(
render(
<MemoryRouter>
<MockedProvider>
<MockedWalletProvider>
<AppStateProvider>
<Proposal restData={null} proposal={proposal} />
</AppStateProvider>
</MockedWalletProvider>
<VegaWalletProvider config={vegaWalletConfig}>
<Proposal restData={null} proposal={proposal} />
</VegaWalletProvider>
</MockedProvider>
</MemoryRouter>
);
@@ -23,7 +23,7 @@ export interface ProposalProps {
export const Proposal = ({ proposal, restData }: ProposalProps) => {
const { t } = useTranslation();
const { submit, finalizedVote, transaction } = useVoteSubmit();
const { submit, Dialog, finalizedVote, transaction } = useVoteSubmit();
const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote);
return (
@@ -60,7 +60,7 @@ export const Proposal = ({ proposal, restData }: ProposalProps) => {
<ProposalDescription description={proposal.rationale.description} />
</div>
<div className="mb-4 flex flex-col gap-0">
<div className="mb-4">
{proposal.__typename === 'Proposal' ? (
<ProposalChangeDetails
proposal={proposal}
@@ -88,6 +88,7 @@ export const Proposal = ({ proposal, restData }: ProposalProps) => {
<UserVote
proposal={proposal}
submit={submit}
dialog={Dialog}
transaction={transaction}
voteState={voteState}
voteDatetime={voteDatetime}
@@ -1,14 +1,15 @@
import { BrowserRouter as Router } from 'react-router-dom';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { render, screen } from '@testing-library/react';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { ProposalsListItemDetails } from './proposals-list-item-details';
import { mockWalletContext } from '../../test-helpers/mocks';
const renderComponent = (id: string) =>
render(
<Router>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposalsListItemDetails id={id} />
</AppStateProvider>
</VegaWalletContext.Provider>
</Router>
);
@@ -206,7 +206,7 @@ export const ProposalsList = ({
/>
)}
<section className="-mx-4 p-4 mb-8 bg-vega-cdark-900 rounded-l-sm">
<section className="-mx-4 p-4 mb-8 bg-vega-dark-100">
<SubHeading title={t('openProposals')} />
{sortedProposals.open.length > 0 ||
@@ -1,32 +1,25 @@
import { act, render, screen } from '@testing-library/react';
import {
MockedWalletProvider,
mockConfig,
} from '@vegaprotocol/wallet-react/testing';
import { render, screen } from '@testing-library/react';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { ProposalFormSubmit } from './proposal-form-submit';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
const renderComponent = (isSubmitting: boolean) => {
const renderComponent = (
context: VegaWalletContextShape,
isSubmitting: boolean
) => {
render(
<MockedWalletProvider>
<AppStateProvider>
<AppStateProvider>
<VegaWalletContext.Provider value={context}>
<ProposalFormSubmit isSubmitting={isSubmitting} />
</AppStateProvider>
</MockedWalletProvider>
</VegaWalletContext.Provider>
</AppStateProvider>
);
};
describe('Proposal Form Submit', () => {
const pubKey = { publicKey: '123456__123456', name: 'test' };
afterEach(() => {
act(() => {
mockConfig.reset();
});
});
it('should display connection message and button if wallet not connected', () => {
renderComponent(false);
renderComponent({ pubKey: null } as VegaWalletContextShape, false);
expect(
screen.getByText('Connect your wallet to submit a proposal')
@@ -37,22 +30,28 @@ describe('Proposal Form Submit', () => {
});
it('should display submit button if wallet is connected', () => {
mockConfig.store.setState({
pubKey: pubKey.publicKey,
keys: [pubKey],
});
renderComponent(false);
const pubKey = { publicKey: '123456__123456', name: 'test' };
renderComponent(
{
pubKey: pubKey.publicKey,
pubKeys: [pubKey],
} as VegaWalletContextShape,
false
);
expect(screen.getByTestId('proposal-submit')).toHaveTextContent(
'Submit proposal'
);
});
it('should display submitting button text if wallet is connected and submitting', () => {
mockConfig.store.setState({
pubKey: pubKey.publicKey,
keys: [pubKey],
});
renderComponent(true);
const pubKey = { publicKey: '123456__123456', name: 'test' };
renderComponent(
{
pubKey: pubKey.publicKey,
pubKeys: [pubKey],
} as VegaWalletContextShape,
true
);
expect(screen.getByTestId('proposal-submit')).toHaveTextContent(
'Submitting proposal'
);
@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next';
import { Button } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
interface ProposalFormSubmitProps {
@@ -1,24 +1,19 @@
import {
VegaTransactionDialog,
getProposalDialogIcon,
getProposalDialogIntent,
useGetProposalDialogTitle,
} from '@vegaprotocol/proposals';
import type {
ProposalEventFieldsFragment,
VegaTxState,
} from '@vegaprotocol/proposals';
import type { ProposalEventFieldsFragment } from '@vegaprotocol/proposals';
import type { DialogProps } from '@vegaprotocol/proposals';
interface ProposalFormTransactionDialogProps {
finalizedProposal: ProposalEventFieldsFragment | null;
transaction: VegaTxState;
onChange: (open: boolean) => void;
TransactionDialog: (props: DialogProps) => JSX.Element;
}
export const ProposalFormTransactionDialog = ({
finalizedProposal,
transaction,
onChange,
TransactionDialog,
}: ProposalFormTransactionDialogProps) => {
const title = useGetProposalDialogTitle(finalizedProposal?.state);
// Render a custom complete UI if the proposal was rejected otherwise
@@ -29,16 +24,13 @@ export const ProposalFormTransactionDialog = ({
return (
<div data-testid="proposal-transaction-dialog">
<VegaTransactionDialog
<TransactionDialog
title={title}
intent={getProposalDialogIntent(finalizedProposal?.state)}
icon={getProposalDialogIcon(finalizedProposal?.state)}
content={{
Complete: completeContent,
}}
transaction={transaction}
isOpen={transaction.dialogOpen}
onChange={onChange}
/>
</div>
);
@@ -1,8 +1,10 @@
import { render, screen } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
import { MockedProvider } from '@apollo/client/testing';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import {
lastWeek,
mockWalletContext,
networkParamsQueryMock,
nextWeek,
} from '../../test-helpers/mocks';
@@ -46,7 +48,9 @@ const renderComponent = (
render(
<Router>
<MockedProvider mocks={mocks}>
<VoteBreakdown proposal={proposal} />
<VegaWalletContext.Provider value={mockWalletContext}>
<VoteBreakdown proposal={proposal} />
</VegaWalletContext.Provider>
</MockedProvider>
</Router>
);
@@ -56,7 +60,6 @@ describe('VoteBreakdown', () => {
jest.useFakeTimers();
jest.setSystemTime(0);
});
afterAll(() => {
jest.useRealTimers();
});
@@ -15,8 +15,8 @@ import {
type VoteFieldsFragment,
} from '../../__generated__/Proposals';
import { useBatchVoteInformation } from '../../hooks/use-vote-information';
import { getIndicatorStyle } from '../proposal/colours';
import { MarketName } from '../proposal/market-name';
import { Indicator } from '../proposal/indicator';
export const CompactVotes = ({ number }: { number: BigNumber }) => (
<CompactNumber
@@ -300,11 +300,13 @@ const VoteBreakdownBatchSubProposal = ({
</>
) : null;
const indicatorElement = indicator && <Indicator indicator={indicator} />;
const indicatorElement = indicator && (
<span className={getIndicatorStyle(indicator)}>{indicator}</span>
);
return (
<div className="mb-6">
<div className="flex items-center gap-3 mb-3">
<div className="flex items-baseline gap-3 mb-3">
{indicatorElement}
<h4>
{t(terms.change.__typename)} {marketName}
@@ -1,5 +1,5 @@
import { captureMessage } from '@sentry/minimal';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { VoteValue } from '@vegaprotocol/types';
import { useEffect, useState } from 'react';
import { useUserVoteQuery } from './__generated__/Vote';
@@ -1,19 +1,20 @@
import { useTranslation } from 'react-i18next';
import { Icon, ExternalLink } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { ProposalState } from '@vegaprotocol/types';
import { ConnectToVega } from '../../../../components/connect-to-vega';
import { VoteButtonsContainer } from './vote-buttons';
import { SubHeading } from '../../../../components/heading';
import { type VoteValue } from '@vegaprotocol/types';
import { type VegaTxState } from '@vegaprotocol/proposals';
import { type DialogProps, type VegaTxState } from '@vegaprotocol/proposals';
import { type VoteState } from './use-user-vote';
import { type Proposal, type BatchProposal } from '../../types';
interface UserVoteProps {
proposal: Proposal | BatchProposal;
transaction: VegaTxState;
transaction: VegaTxState | null;
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
dialog: (props: DialogProps) => JSX.Element;
voteState: VoteState | null;
voteDatetime: Date | null;
}
@@ -22,6 +23,7 @@ export const UserVote = ({
proposal,
submit,
transaction,
dialog,
voteState,
voteDatetime,
}: UserVoteProps) => {
@@ -54,6 +56,7 @@ export const UserVote = ({
className="flex"
submit={submit}
transaction={transaction}
dialog={dialog}
/>
)
) : (
@@ -2,20 +2,33 @@ import { render, screen } from '@testing-library/react';
import { VoteTransactionDialog } from './vote-transaction-dialog';
import { VoteState } from './use-user-vote';
import { VegaTxStatus } from '@vegaprotocol/proposals';
import { ConnectorErrors, unknownError } from '@vegaprotocol/wallet';
describe('VoteTransactionDialog', () => {
const mockTransactionDialog = jest.fn(({ title, content }) => (
<div>
<div>{title}</div>
<div>{content?.Complete}</div>
</div>
));
it('renders without crashing', () => {
render(
<VoteTransactionDialog
voteState={VoteState.Yes}
transaction={null}
TransactionDialog={mockTransactionDialog}
/>
);
expect(screen.getByTestId('vote-transaction-dialog')).toBeInTheDocument();
});
it('renders with txRequested title when voteState is Requested', () => {
render(
<VoteTransactionDialog
voteState={VoteState.Requested}
transaction={{
error: null,
txHash: null,
signature: null,
status: VegaTxStatus.Requested,
dialogOpen: true,
}}
transaction={null}
TransactionDialog={mockTransactionDialog}
/>
);
@@ -26,13 +39,8 @@ describe('VoteTransactionDialog', () => {
render(
<VoteTransactionDialog
voteState={VoteState.Pending}
transaction={{
error: null,
txHash: null,
signature: null,
status: VegaTxStatus.Pending,
dialogOpen: true,
}}
transaction={null}
TransactionDialog={mockTransactionDialog}
/>
);
@@ -43,13 +51,8 @@ describe('VoteTransactionDialog', () => {
render(
<VoteTransactionDialog
voteState={VoteState.Yes} // or any other state other than Requested or Pending
transaction={{
error: null,
txHash: null,
signature: null,
status: VegaTxStatus.Complete,
dialogOpen: true,
}}
transaction={null}
TransactionDialog={mockTransactionDialog}
/>
);
@@ -62,18 +65,17 @@ describe('VoteTransactionDialog', () => {
<VoteTransactionDialog
voteState={VoteState.Failed}
transaction={{
error: unknownError(),
error: { message: 'Custom error test message', name: 'blah' },
txHash: null,
signature: null,
status: VegaTxStatus.Error,
dialogOpen: true,
dialogOpen: false,
}}
TransactionDialog={mockTransactionDialog}
/>
);
expect(
screen.getByText(ConnectorErrors.unknown.message)
).toBeInTheDocument();
expect(screen.getByText('Custom error test message')).toBeInTheDocument();
});
it('renders default error message when voteState is failed and no error message exists on the tx', () => {
@@ -84,9 +86,10 @@ describe('VoteTransactionDialog', () => {
error: null,
txHash: null,
signature: null,
status: VegaTxStatus.Complete,
dialogOpen: true,
status: VegaTxStatus.Error,
dialogOpen: false,
}}
TransactionDialog={mockTransactionDialog}
/>
);
@@ -97,13 +100,8 @@ describe('VoteTransactionDialog', () => {
render(
<VoteTransactionDialog
voteState={VoteState.Yes}
transaction={{
error: null,
txHash: null,
signature: null,
status: VegaTxStatus.Default,
dialogOpen: true,
}}
transaction={null}
TransactionDialog={mockTransactionDialog}
/>
);
@@ -1,77 +1,120 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
import { fireEvent, render, screen } from '@testing-library/react';
import BigNumber from 'bignumber.js';
import { VoteButtons, type VoteButtonsProps } from './vote-buttons';
import { VoteButtons } from './vote-buttons';
import { VoteState } from './use-user-vote';
import { ProposalState } from '@vegaprotocol/types';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { mockWalletContext } from '../../test-helpers/mocks';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { MockedProvider } from '@apollo/react-testing';
import { VegaTxStatus } from '@vegaprotocol/proposals';
import {
MockedWalletProvider,
mockConfig,
} from '@vegaprotocol/wallet-react/testing';
describe('Vote buttons', () => {
const key = { publicKey: '0x123', name: 'key 1' };
const transaction = {
status: VegaTxStatus.Default,
error: null,
txHash: null,
signature: null,
dialogOpen: false,
};
const props = {
voteState: VoteState.NotCast,
voteDatetime: null,
proposalState: ProposalState.STATE_OPEN,
proposalId: null,
minVoterBalance: null,
spamProtectionMinTokens: null,
currentStakeAvailable: new BigNumber(1),
submit: () => Promise.resolve(),
transaction,
};
const renderComponent = (testProps?: Partial<VoteButtonsProps>) => {
return render(
it('should render successfully', () => {
const { baseElement } = render(
<AppStateProvider>
<MockedProvider>
<MockedWalletProvider>
<VoteButtons {...props} {...testProps} />
</MockedWalletProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<VoteButtons
voteState={VoteState.NotCast}
voteDatetime={null}
proposalState={ProposalState.STATE_OPEN}
proposalId={null}
minVoterBalance={null}
spamProtectionMinTokens={null}
currentStakeAvailable={new BigNumber(1)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
transaction={null}
/>
</VegaWalletContext.Provider>
</MockedProvider>
</AppStateProvider>
);
};
beforeEach(() => {
mockConfig.store.setState({ pubKey: key.publicKey, keys: [key] });
});
afterEach(() => {
act(() => {
mockConfig.reset();
});
});
it('should render successfully', () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
});
it('should explain that voting is closed if the proposal is not open', () => {
renderComponent({ proposalState: ProposalState.STATE_PASSED });
render(
<AppStateProvider>
<MockedProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<VoteButtons
voteState={VoteState.NotCast}
voteDatetime={null}
proposalState={ProposalState.STATE_PASSED}
proposalId={null}
minVoterBalance={null}
spamProtectionMinTokens={null}
currentStakeAvailable={new BigNumber(1)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
transaction={null}
/>
</VegaWalletContext.Provider>
</MockedProvider>
</AppStateProvider>
);
expect(screen.getByText('Voting has ended.')).toBeTruthy();
});
it('should provide a connect wallet prompt if no pubkey', () => {
mockConfig.reset();
renderComponent();
const mockWalletNoPubKeyContext = {
pubKey: null,
pubKeys: [],
isReadOnly: false,
sendTx: jest.fn().mockReturnValue(Promise.resolve(null)),
connect: jest.fn(),
disconnect: jest.fn(),
selectPubKey: jest.fn(),
connector: null,
} as unknown as VegaWalletContextShape;
render(
<AppStateProvider>
<MockedProvider>
<VegaWalletContext.Provider value={mockWalletNoPubKeyContext}>
<VoteButtons
voteState={VoteState.NotCast}
voteDatetime={null}
proposalState={ProposalState.STATE_OPEN}
proposalId={null}
minVoterBalance={null}
spamProtectionMinTokens={null}
currentStakeAvailable={new BigNumber(1)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
transaction={null}
/>
</VegaWalletContext.Provider>
</MockedProvider>
</AppStateProvider>
);
expect(screen.getByTestId('connect-wallet')).toBeTruthy();
});
it('should tell the user they need tokens if their current stake is 0', () => {
renderComponent({ currentStakeAvailable: new BigNumber(0) });
render(
<AppStateProvider>
<MockedProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<VoteButtons
voteState={VoteState.NotCast}
voteDatetime={null}
proposalState={ProposalState.STATE_OPEN}
proposalId={null}
minVoterBalance={null}
spamProtectionMinTokens={null}
currentStakeAvailable={new BigNumber(0)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
transaction={null}
/>
</VegaWalletContext.Provider>
</MockedProvider>
</AppStateProvider>
);
expect(
screen.getByText(
'You need some VEGA tokens to participate in governance.'
@@ -80,10 +123,26 @@ describe('Vote buttons', () => {
});
it('should tell the user of the minimum requirements if they have some, but not enough tokens', () => {
renderComponent({
minVoterBalance: '2000000000000000000',
spamProtectionMinTokens: '1000000000000000000',
});
render(
<AppStateProvider>
<MockedProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<VoteButtons
voteState={VoteState.NotCast}
voteDatetime={null}
proposalState={ProposalState.STATE_OPEN}
proposalId={null}
minVoterBalance="2000000000000000000"
spamProtectionMinTokens="1000000000000000000"
currentStakeAvailable={new BigNumber(1)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
transaction={null}
/>
</VegaWalletContext.Provider>
</MockedProvider>
</AppStateProvider>
);
expect(
screen.getByText(
'You must have at least 2 VEGA associated to vote on this proposal'
@@ -92,23 +151,51 @@ describe('Vote buttons', () => {
});
it('should show you voted if vote state is correct, and if the proposal is still open, it will display a change vote button', () => {
renderComponent({
voteState: VoteState.Yes,
minVoterBalance: '2000000000000000000',
spamProtectionMinTokens: '1000000000000000000',
currentStakeAvailable: new BigNumber(10),
});
render(
<AppStateProvider>
<MockedProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<VoteButtons
voteState={VoteState.Yes}
voteDatetime={null}
proposalState={ProposalState.STATE_OPEN}
proposalId={null}
minVoterBalance="2000000000000000000"
spamProtectionMinTokens="1000000000000000000"
currentStakeAvailable={new BigNumber(10)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
transaction={null}
/>
</VegaWalletContext.Provider>
</MockedProvider>
</AppStateProvider>
);
expect(screen.getByTestId('you-voted')).toBeInTheDocument();
expect(screen.getByTestId('change-vote-button')).toBeInTheDocument();
});
it('should allow you to change your vote', () => {
renderComponent({
voteState: VoteState.No,
minVoterBalance: '2000000000000000000',
spamProtectionMinTokens: '1000000000000000000',
currentStakeAvailable: new BigNumber(10),
});
render(
<AppStateProvider>
<MockedProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<VoteButtons
voteState={VoteState.No}
voteDatetime={null}
proposalState={ProposalState.STATE_OPEN}
proposalId={null}
minVoterBalance="2000000000000000000"
spamProtectionMinTokens="1000000000000000000"
currentStakeAvailable={new BigNumber(10)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
transaction={null}
/>
</VegaWalletContext.Provider>
</MockedProvider>
</AppStateProvider>
);
fireEvent.click(screen.getByTestId('change-vote-button'));
expect(screen.getByTestId('vote-buttons')).toBeInTheDocument();
});
@@ -1,7 +1,7 @@
import { format } from 'date-fns';
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useVegaWallet, useDialogStore } from '@vegaprotocol/wallet-react';
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import {
AsyncRenderer,
Button,
@@ -17,7 +17,7 @@ import { VoteState } from './use-user-vote';
import { ProposalMinRequirements, ProposalUserAction } from '../shared';
import { VoteTransactionDialog } from './vote-transaction-dialog';
import { useVoteButtonsQuery } from './__generated__/Stake';
import type { VegaTxState } from '@vegaprotocol/proposals';
import type { DialogProps, VegaTxState } from '@vegaprotocol/proposals';
import { filterAcceptableGraphqlErrors } from '../../../../lib/party';
import {
NetworkParams,
@@ -32,7 +32,8 @@ interface VoteButtonsContainerProps {
proposalId: string | null;
proposalState: ProposalState;
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
transaction: VegaTxState;
transaction: VegaTxState | null;
dialog: (props: DialogProps) => JSX.Element;
className?: string;
}
@@ -135,16 +136,17 @@ export const VoteButtonsContainer = (props: VoteButtonsContainerProps) => {
);
};
export interface VoteButtonsProps {
interface VoteButtonsProps {
voteState: VoteState | null;
voteDatetime: Date | null;
proposalState: ProposalState;
proposalId: string | null;
proposalState: ProposalState;
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
transaction: VegaTxState | null;
dialog: (props: DialogProps) => JSX.Element;
currentStakeAvailable: BigNumber;
minVoterBalance: string | null;
spamProtectionMinTokens: string | null;
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
transaction: VegaTxState;
}
export const VoteButtons = ({
@@ -157,10 +159,13 @@ export const VoteButtons = ({
spamProtectionMinTokens,
submit,
transaction,
dialog: Dialog,
}: VoteButtonsProps) => {
const { t } = useTranslation();
const { pubKey } = useVegaWallet();
const openVegaWalletDialog = useDialogStore((store) => store.open);
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
const [changeVote, setChangeVote] = React.useState(false);
const proposalVotable = useMemo(
() =>
@@ -179,7 +184,11 @@ export const VoteButtons = ({
if (!pubKey) {
return (
<div data-testid="connect-wallet">
<ButtonLink onClick={openVegaWalletDialog}>
<ButtonLink
onClick={() => {
openVegaWalletDialog();
}}
>
{t('connectVegaWallet')}
</ButtonLink>{' '}
{t('toVote')}
@@ -292,7 +301,11 @@ export const VoteButtons = ({
</p>
)
)}
<VoteTransactionDialog voteState={voteState} transaction={transaction} />
<VoteTransactionDialog
voteState={voteState}
transaction={transaction}
TransactionDialog={Dialog}
/>
</>
);
};
@@ -1,13 +1,11 @@
import { t } from '@vegaprotocol/i18n';
import { VoteState } from './use-user-vote';
import {
VegaTransactionDialog,
type VegaTxState,
} from '@vegaprotocol/proposals';
import type { DialogProps, VegaTxState } from '@vegaprotocol/proposals';
interface VoteTransactionDialogProps {
voteState: VoteState;
transaction: VegaTxState;
transaction: VegaTxState | null;
TransactionDialog: (props: DialogProps) => JSX.Element;
}
const dialogTitle = (voteState: VoteState): string | undefined => {
@@ -24,23 +22,22 @@ const dialogTitle = (voteState: VoteState): string | undefined => {
export const VoteTransactionDialog = ({
voteState,
transaction,
TransactionDialog,
}: VoteTransactionDialogProps) => {
// Render a custom message if the voting fails otherwise
// pass undefined so that the default vega transaction dialog UI gets used
const customMessage =
voteState === VoteState.Failed ? (
<p>{transaction.error?.message || t('voteError')}</p>
<p>{transaction?.error?.message || t('voteError')}</p>
) : undefined;
return (
<div data-testid="vote-transaction-dialog">
<VegaTransactionDialog
<TransactionDialog
title={dialogTitle(voteState)}
transaction={transaction}
content={{
Complete: customMessage,
}}
isOpen={transaction.dialogOpen}
/>
</div>
);
@@ -1,12 +1,13 @@
import { render, screen } from '@testing-library/react';
import { ProposeFreeform } from './propose-freeform';
import { MockedProvider } from '@apollo/client/testing';
import { mockWalletContext } from '../../test-helpers/mocks';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { MemoryRouter as Router } from 'react-router-dom';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import type { MockedResponse } from '@apollo/client/testing';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
import { MockedWalletProvider } from '@vegaprotocol/wallet-react/testing';
jest.mock('@vegaprotocol/environment', () => ({
...jest.requireActual('@vegaprotocol/environment'),
@@ -71,19 +72,18 @@ const updateMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
},
};
const renderComponent = () => {
return render(
const renderComponent = () =>
render(
<Router>
<MockedProvider mocks={[updateMarketNetworkParamsQueryMock]}>
<MockedWalletProvider>
<AppStateProvider>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeFreeform />
</AppStateProvider>
</MockedWalletProvider>
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
</Router>
);
};
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
@@ -51,8 +51,7 @@ export const ProposeFreeform = () => {
watch,
trigger,
} = useForm<FreeformProposalFormFields>();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const assembleProposal = (fields: FreeformProposalFormFields) => {
const isVoteDeadlineAtMinimum =
@@ -170,8 +169,7 @@ export const ProposeFreeform = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
TransactionDialog={Dialog}
/>
</form>
</div>
@@ -1,12 +1,13 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { ProposeNetworkParameter } from './propose-network-parameter';
import { MockedProvider } from '@apollo/client/testing';
import { mockWalletContext } from '../../test-helpers/mocks';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { MemoryRouter as Router } from 'react-router-dom';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
import type { MockedResponse } from '@apollo/client/testing';
import { MockedWalletProvider } from '@vegaprotocol/wallet-react/testing';
jest.mock('@vegaprotocol/environment', () => ({
...jest.requireActual('@vegaprotocol/environment'),
@@ -71,27 +72,26 @@ const updateMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
},
};
const renderComponent = () => {
return render(
const renderComponent = () =>
render(
<Router>
<MockedProvider mocks={[updateMarketNetworkParamsQueryMock]}>
<MockedWalletProvider>
<AppStateProvider>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeNetworkParameter />
</AppStateProvider>
</MockedWalletProvider>
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
</Router>
);
};
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
describe('Propose Network Parameter', () => {
it('should render successfully', () => {
it('should render successfully', async () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
await expect(baseElement).toBeTruthy();
});
it('should render the correct title', async () => {
@@ -91,8 +91,7 @@ export const ProposeNetworkParameter = () => {
watch,
trigger,
} = useForm<NetworkParameterProposalFormFields>();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const selectedParamEntry = params
? Object.entries(params).find(([key]) => key === selectedNetworkParam)
@@ -313,8 +312,7 @@ export const ProposeNetworkParameter = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
TransactionDialog={Dialog}
/>
</form>
</div>
@@ -1,12 +1,13 @@
import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter as Router } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { mockWalletContext } from '../../test-helpers/mocks';
import { ProposeNewAsset } from './propose-new-asset';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import type { MockedResponse } from '@apollo/client/testing';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
import { MockedWalletProvider } from '@vegaprotocol/wallet-react/testing';
jest.mock('@vegaprotocol/environment', () => ({
...jest.requireActual('@vegaprotocol/environment'),
@@ -71,27 +72,26 @@ const newAssetNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
},
};
const renderComponent = () => {
return render(
const renderComponent = () =>
render(
<Router>
<MockedProvider mocks={[newAssetNetworkParamsQueryMock]}>
<MockedWalletProvider>
<AppStateProvider>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeNewAsset />
</AppStateProvider>
</MockedWalletProvider>
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
</Router>
);
};
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
describe('Propose New Asset', () => {
it('should render successfully', () => {
it('should render successfully', async () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
await expect(baseElement).toBeTruthy();
});
it('should render the title', async () => {
@@ -64,8 +64,7 @@ export const ProposeNewAsset = () => {
watch,
trigger,
} = useForm<NewAssetProposalFormFields>();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const assembleProposal = (fields: NewAssetProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
@@ -233,8 +232,7 @@ export const ProposeNewAsset = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
TransactionDialog={Dialog}
/>
</form>
</div>
@@ -1,12 +1,13 @@
import { render, screen } from '@testing-library/react';
import { ProposeNewMarket } from './propose-new-market';
import { MockedProvider } from '@apollo/client/testing';
import { mockWalletContext } from '../../test-helpers/mocks';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { BrowserRouter as Router } from 'react-router-dom';
import type { MockedResponse } from '@apollo/client/testing';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
import { MockedWalletProvider } from '@vegaprotocol/wallet-react/testing';
jest.mock('@vegaprotocol/environment', () => ({
...jest.requireActual('@vegaprotocol/environment'),
@@ -71,27 +72,26 @@ const newMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
},
};
const renderComponent = () => {
return render(
const renderComponent = () =>
render(
<Router>
<MockedProvider mocks={[newMarketNetworkParamsQueryMock]}>
<MockedWalletProvider>
<AppStateProvider>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeNewMarket />
</AppStateProvider>
</MockedWalletProvider>
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
</Router>
);
};
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
describe('Propose New Market', () => {
it('should render successfully', () => {
it('should render successfully', async () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
await expect(baseElement).toBeTruthy();
});
it('should render the form components', async () => {
@@ -62,8 +62,7 @@ export const ProposeNewMarket = () => {
watch,
trigger,
} = useForm<NewMarketProposalFormFields>();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const assembleProposal = (fields: NewMarketProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
@@ -215,8 +214,7 @@ export const ProposeNewMarket = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
TransactionDialog={Dialog}
/>
</form>
</div>
@@ -3,6 +3,8 @@ import type { MockedResponse } from '@apollo/client/testing';
import { addHours, getTime } from 'date-fns';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { MockedProvider } from '@apollo/client/testing';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import * as Schema from '@vegaprotocol/types';
import { ProposeRaw } from './propose-raw';
import { ProposalEventDocument } from '@vegaprotocol/proposals';
@@ -10,11 +12,6 @@ import type { ProposalEventSubscription } from '@vegaprotocol/proposals';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
import {
MockedWalletProvider,
mockConfig,
} from '@vegaprotocol/wallet-react/testing';
import { userRejectedError } from '@vegaprotocol/wallet';
const paramsDelay = 20;
@@ -106,15 +103,23 @@ describe('Raw proposal form', () => {
},
delay: 300,
};
const setup = () => {
const setup = (mockSendTx = jest.fn()) => {
return render(
<AppStateProvider>
<MockedProvider
mocks={[rawProposalNetworkParamsQueryMock, mockProposalEvent]}
>
<MockedWalletProvider>
<VegaWalletContext.Provider
value={
{
pubKey,
sendTx: mockSendTx,
links: { explorer: 'explorer' },
} as unknown as VegaWalletContextShape
}
>
<ProposeRaw />
</MockedWalletProvider>
</VegaWalletContext.Provider>
</MockedProvider>
</AppStateProvider>
);
@@ -122,22 +127,15 @@ describe('Raw proposal form', () => {
beforeAll(() => {
jest.useFakeTimers();
mockConfig.store.setState({ status: 'connected', pubKey: '0x123' });
});
afterAll(() => {
jest.useRealTimers();
mockConfig.reset();
});
afterEach(() => {
jest.clearAllMocks();
});
it('handles validation', async () => {
const mockSendTx = jest.spyOn(mockConfig, 'sendTransaction');
setup();
const mockSendTx = jest.fn().mockReturnValue(Promise.resolve());
setup(mockSendTx);
expect(await screen.findByTestId('proposal-submit')).toBeTruthy();
await act(async () => {
@@ -164,25 +162,20 @@ describe('Raw proposal form', () => {
});
it('sends the transaction', async () => {
const mockSendTx = jest
.spyOn(mockConfig, 'sendTransaction')
.mockReturnValue(
new Promise((resolve) => {
setTimeout(
() =>
resolve({
transactionHash: 'tx-hash',
signature:
'cfe592d169f87d0671dd447751036d0dddc165b9c4b65e5a5060e2bbadd1aa726d4cbe9d3c3b327bcb0bff4f83999592619a2493f9bbd251fae99ce7ce766909',
sentAt: new Date().toISOString(),
receivedAt: new Date().toISOString(),
}),
100
);
})
);
setup();
const mockSendTx = jest.fn().mockReturnValue(
new Promise((resolve) => {
setTimeout(
() =>
resolve({
transactionHash: 'tx-hash',
signature:
'cfe592d169f87d0671dd447751036d0dddc165b9c4b65e5a5060e2bbadd1aa726d4cbe9d3c3b327bcb0bff4f83999592619a2493f9bbd251fae99ce7ce766909',
}),
100
);
})
);
setup(mockSendTx);
await act(async () => {
jest.advanceTimersByTime(paramsDelay);
@@ -213,12 +206,8 @@ describe('Raw proposal form', () => {
fireEvent.click(screen.getByTestId('proposal-submit'));
});
expect(mockSendTx).toHaveBeenCalledWith({
publicKey: pubKey,
sendingMode: 'TYPE_SYNC',
transaction: {
proposalSubmission: JSON.parse(inputJSON),
},
expect(mockSendTx).toHaveBeenCalledWith(pubKey, {
proposalSubmission: JSON.parse(inputJSON),
});
expect(screen.getByTestId('dialog-title')).toHaveTextContent(
@@ -243,12 +232,12 @@ describe('Raw proposal form', () => {
});
it('can be rejected by the user', async () => {
jest.spyOn(mockConfig, 'sendTransaction').mockReturnValue(
new Promise((_, reject) => {
setTimeout(() => reject(userRejectedError()), 100);
const mockSendTx = jest.fn().mockReturnValue(
new Promise((resolve) => {
setTimeout(() => resolve(null), 100);
})
);
setup();
setup(mockSendTx);
await act(async () => {
jest.advanceTimersByTime(paramsDelay);
@@ -52,8 +52,7 @@ export const ProposeRaw = () => {
handleSubmit,
formState: { isSubmitting, errors },
} = useForm<RawProposalFormFields>();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const hasError = Boolean(errors.rawProposalData?.message);
@@ -153,8 +152,7 @@ export const ProposeRaw = () => {
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
TransactionDialog={Dialog}
/>
</form>
</div>
@@ -1,12 +1,13 @@
import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter as Router } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { mockWalletContext } from '../../test-helpers/mocks';
import { ProposeUpdateAsset } from './propose-update-asset';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import type { MockedResponse } from '@apollo/client/testing';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
import { MockedWalletProvider } from '@vegaprotocol/wallet-react/testing';
jest.mock('@vegaprotocol/environment', () => ({
...jest.requireActual('@vegaprotocol/environment'),
@@ -71,27 +72,26 @@ const updateAssetNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
},
};
const renderComponent = () => {
return render(
const renderComponent = () =>
render(
<Router>
<MockedProvider mocks={[updateAssetNetworkParamsQueryMock]}>
<MockedWalletProvider>
<AppStateProvider>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeUpdateAsset />
</AppStateProvider>
</MockedWalletProvider>
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
</Router>
);
};
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
describe('Propose Update Asset', () => {
it('should render successfully', () => {
it('should render successfully', async () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
await expect(baseElement).toBeTruthy();
});
it('should render the title', async () => {
@@ -62,8 +62,7 @@ export const ProposeUpdateAsset = () => {
watch,
trigger,
} = useForm<UpdateAssetProposalFormFields>();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const assembleProposal = (fields: UpdateAssetProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
@@ -219,8 +218,7 @@ export const ProposeUpdateAsset = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
TransactionDialog={Dialog}
/>
</form>
</div>
@@ -2,14 +2,15 @@ import type { MockedResponse } from '@apollo/client/testing';
import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter as Router } from 'react-router-dom';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { mockWalletContext } from '../../test-helpers/mocks';
import { ProposeUpdateMarket } from './propose-update-market';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
import type { ProposalMarketsQueryQuery } from './__generated__/UpdateMarket';
import { ProposalMarketsQueryDocument } from './__generated__/UpdateMarket';
import { ProposalState } from '@vegaprotocol/types';
import { MockedWalletProvider } from '@vegaprotocol/wallet-react/testing';
const updateMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
request: {
@@ -216,30 +217,29 @@ const marketQueryMock: MockedResponse<ProposalMarketsQueryQuery> = {
},
};
const renderComponent = () => {
return render(
const renderComponent = () =>
render(
<MockedProvider
mocks={[updateMarketNetworkParamsQueryMock, marketQueryMock]}
addTypename={false}
>
<Router>
<MockedWalletProvider>
<AppStateProvider>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeUpdateMarket />
</AppStateProvider>
</MockedWalletProvider>
</VegaWalletContext.Provider>
</AppStateProvider>
</Router>
</MockedProvider>
);
};
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
describe('Propose Update Market', () => {
it('should render successfully', () => {
it('should render successfully', async () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
await expect(baseElement).toBeTruthy();
});
it('should render the title', async () => {
@@ -109,8 +109,7 @@ export const ProposeUpdateMarket = () => {
watch,
trigger,
} = useForm<UpdateMarketProposalFormFields>();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const assembleProposal = (fields: UpdateMarketProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
@@ -324,8 +323,7 @@ export const ProposeUpdateMarket = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
TransactionDialog={Dialog}
/>
</form>
</div>
@@ -1,17 +1,28 @@
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
import type { MockedResponse } from '@apollo/client/testing';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import type { PubKey, VegaWalletContextShape } from '@vegaprotocol/wallet';
import type { VoteValue } from '@vegaprotocol/types';
import type { UserVoteQuery } from '../components/vote-details/__generated__/Vote';
import { UserVoteDocument } from '../components/vote-details/__generated__/Vote';
import faker from 'faker';
import { type Key } from '@vegaprotocol/wallet';
export const mockPubkey: Key = {
export const mockPubkey: PubKey = {
publicKey: '0x123',
name: 'test key 1',
};
export const mockWalletContext = {
pubKey: mockPubkey.publicKey,
pubKeys: [mockPubkey],
isReadOnly: false,
sendTx: jest.fn().mockReturnValue(Promise.resolve(null)),
connect: jest.fn(),
disconnect: jest.fn(),
selectPubKey: jest.fn(),
connector: null,
} as unknown as VegaWalletContextShape;
const mockEthereumConfig = {
network_id: '3',
chain_id: '3',
@@ -1,11 +1,13 @@
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import { useDialogStore } from '@vegaprotocol/wallet-react';
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import { Button } from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../components/heading';
export const ConnectToSeeRewards = () => {
const openVegaWalletDialog = useDialogStore((store) => store.open);
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
const { t } = useTranslation();
const classes = classNames(
@@ -1,10 +1,11 @@
import { useMemo, useState } from 'react';
import { useMemo, useEffect, useState, useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { AsyncRenderer, Pagination } from '@vegaprotocol/ui-toolkit';
import { removePaginationWrapper } from '@vegaprotocol/utils';
import type { EpochFieldsFragment } from '../home/__generated__/Rewards';
import { useRewardsQuery } from '../home/__generated__/Rewards';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { ENV } from '../../../config';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { EpochIndividualRewardsTable } from './epoch-individual-rewards-table';
import { generateEpochIndividualRewardsList } from './generate-epoch-individual-rewards-list';
import { calculateEpochOffset } from '../../../lib/epoch-pagination';
@@ -26,16 +27,22 @@ export const EpochIndividualRewards = ({
const [page, setPage] = useState(1);
const { t } = useTranslation();
const { pubKey } = useVegaWallet();
const { delegationsPagination } = ENV;
const { param: marketCreationQuantumMultiple } = useNetworkParam(
'rewards_marketCreationQuantumMultiple'
);
const { data, loading, error } = useRewardsQuery({
const { data, loading, error, refetch } = useRewardsQuery({
notifyOnNetworkStatusChange: true,
variables: {
partyId: pubKey || '',
...calculateEpochOffset({ epochId, page, size: EPOCHS_PAGE_SIZE }),
delegationsPagination: { first: 50 },
fromEpoch: epochId - EPOCHS_PAGE_SIZE,
toEpoch: epochId,
delegationsPagination: delegationsPagination
? {
first: Number(delegationsPagination),
}
: undefined,
},
skip: !pubKey,
});
@@ -63,6 +70,36 @@ export const EpochIndividualRewards = ({
});
}, [data?.party, epochId, epochRewardSummaries, page, rewards]);
const refetchData = useCallback(
async (toPage?: number) => {
const targetPage = toPage ?? page;
await refetch({
partyId: pubKey || '',
...calculateEpochOffset({ epochId, page, size: EPOCHS_PAGE_SIZE }),
delegationsPagination: delegationsPagination
? {
first: Number(delegationsPagination),
}
: undefined,
});
setPage(targetPage);
},
[epochId, page, refetch, delegationsPagination, pubKey]
);
const prevEpochIdRef = useRef<number | null>(null);
useEffect(() => {
if (prevEpochIdRef.current === null) {
prevEpochIdRef.current = epochId;
} else if (epochId !== prevEpochIdRef.current) {
// When the epoch changes, we want to refetch the data to update the current page
refetchData();
}
prevEpochIdRef.current = epochId;
}, [epochId, refetchData]);
// Workarounds for the error handling of AsyncRenderer
const filteredErrors = filterAcceptableGraphqlErrors(error);
const filteredData = data || [];
@@ -94,10 +131,10 @@ export const EpochIndividualRewards = ({
isLoading={loading}
hasPrevPage={page > 1}
hasNextPage={page < totalPages}
onBack={() => setPage((x) => x - 1)}
onNext={() => setPage((x) => x + 1)}
onFirst={() => setPage(1)}
onLast={() => setPage(totalPages)}
onBack={() => refetchData(page - 1)}
onNext={() => refetchData(page + 1)}
onFirst={() => refetchData(1)}
onLast={() => refetchData(totalPages)}
>
{t('Page')} {page}
</Pagination>
@@ -23,6 +23,36 @@ describe('generateEpochIndividualRewardsList', () => {
epoch: { id: '2' },
};
const reward3: RewardFieldsFragment = {
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '200',
percentageOfTotal: '0.2',
receivedAt: new Date(),
asset: { id: 'gbp', symbol: 'GBP', name: 'GBP', decimals: 7 },
party: { id: 'blah' },
epoch: { id: '2' },
};
const reward4: RewardFieldsFragment = {
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '100',
percentageOfTotal: '0.1',
receivedAt: new Date(),
asset: { id: 'usd', symbol: 'USD', name: 'USD', decimals: 6 },
party: { id: 'blah' },
epoch: { id: '1' },
};
const reward5: RewardFieldsFragment = {
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '150',
percentageOfTotal: '0.15',
receivedAt: new Date(),
asset: { id: 'usd', symbol: 'USD', name: 'USD', decimals: 6 },
party: { id: 'blah' },
epoch: { id: '3' },
};
const rewardWrongType: RewardFieldsFragment = {
rewardType: AccountType.ACCOUNT_TYPE_INSURANCE,
amount: '50',
@@ -90,10 +120,26 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '100',
percentageOfTotal: '0.1',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
amount: '0',
percentageOfTotal: '0',
},
},
},
],
@@ -101,7 +147,7 @@ describe('generateEpochIndividualRewardsList', () => {
});
it('should return an array sorted by epoch descending', () => {
const rewards = [reward1, reward2];
const rewards = [reward1, reward2, reward3, reward4];
const result1 = generateEpochIndividualRewardsList({
rewards,
epochId: 2,
@@ -111,7 +157,7 @@ describe('generateEpochIndividualRewardsList', () => {
expect(result1[0].epoch).toEqual(2);
expect(result1[1].epoch).toEqual(1);
const reorderedRewards = [reward2, reward1];
const reorderedRewards = [reward4, reward3, reward2, reward1];
const result2 = generateEpochIndividualRewardsList({
rewards: reorderedRewards,
epochId: 2,
@@ -124,7 +170,7 @@ describe('generateEpochIndividualRewardsList', () => {
it('returns data in the expected shape', () => {
// Just sanity checking the whole structure here
const rewards = [reward1, reward2];
const rewards = [reward1, reward2, reward3, reward4];
const result = generateEpochIndividualRewardsList({
rewards,
epochId: 2,
@@ -135,6 +181,37 @@ describe('generateEpochIndividualRewardsList', () => {
{
epoch: 2,
rewards: [
{
asset: 'GBP',
totalAmount: '200',
decimals: 7,
rewardTypes: {
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '200',
percentageOfTotal: '0.2',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
amount: '0',
percentageOfTotal: '0',
},
},
},
{
asset: 'EUR',
totalAmount: '50',
@@ -144,10 +221,26 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '50',
percentageOfTotal: '0.05',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
amount: '0',
percentageOfTotal: '0',
},
},
},
],
@@ -157,17 +250,33 @@ describe('generateEpochIndividualRewardsList', () => {
rewards: [
{
asset: 'USD',
totalAmount: '100',
totalAmount: '200',
decimals: 6,
rewardTypes: {
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '100',
percentageOfTotal: '0.1',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '100',
percentageOfTotal: '0.1',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
amount: '0',
percentageOfTotal: '0',
},
},
},
],
@@ -176,7 +285,7 @@ describe('generateEpochIndividualRewardsList', () => {
});
it('returns data correctly for the requested epoch range', () => {
const rewards = [reward1, reward2];
const rewards = [reward1, reward2, reward3, reward4, reward5];
const resultPageOne = generateEpochIndividualRewardsList({
rewards,
epochId: 3,
@@ -188,11 +297,74 @@ describe('generateEpochIndividualRewardsList', () => {
expect(resultPageOne).toEqual([
{
epoch: 3,
rewards: [],
rewards: [
{
asset: 'USD',
decimals: 6,
totalAmount: '150',
rewardTypes: {
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '150',
percentageOfTotal: '0.15',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
amount: '0',
percentageOfTotal: '0',
},
},
},
],
},
{
epoch: 2,
rewards: [
{
asset: 'GBP',
totalAmount: '200',
decimals: 7,
rewardTypes: {
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '200',
percentageOfTotal: '0.2',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
amount: '0',
percentageOfTotal: '0',
},
},
},
{
asset: 'EUR',
totalAmount: '50',
@@ -202,10 +374,26 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '50',
percentageOfTotal: '0.05',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
amount: '0',
percentageOfTotal: '0',
},
},
},
],
@@ -226,17 +414,33 @@ describe('generateEpochIndividualRewardsList', () => {
rewards: [
{
asset: 'USD',
totalAmount: '100',
totalAmount: '200',
decimals: 6,
rewardTypes: {
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '100',
percentageOfTotal: '0.1',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '100',
percentageOfTotal: '0.1',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
amount: '0',
percentageOfTotal: '0',
},
},
},
],
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState, useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { AsyncRenderer, Pagination } from '@vegaprotocol/ui-toolkit';
import type { EpochFieldsFragment } from '../home/__generated__/Rewards';
@@ -23,17 +23,37 @@ export const EpochTotalRewards = ({ currentEpoch }: EpochTotalRewardsProps) => {
'rewards_marketCreationQuantumMultiple'
);
const [page, setPage] = useState(1);
const { data, loading, error } = useEpochAssetsRewardsQuery({
const { data, loading, error, refetch } = useEpochAssetsRewardsQuery({
notifyOnNetworkStatusChange: true,
variables: {
epochRewardSummariesFilter: calculateEpochOffset({
epochId,
page: page,
size: EPOCHS_PAGE_SIZE,
}),
epochRewardSummariesFilter: {
fromEpoch: epochId - EPOCHS_PAGE_SIZE,
},
},
});
const refetchData = useCallback(
async (toPage?: number) => {
const targetPage = toPage ?? page;
await refetch({
epochRewardSummariesFilter: calculateEpochOffset({
epochId,
page: targetPage,
size: EPOCHS_PAGE_SIZE,
}),
});
setPage(targetPage);
},
[epochId, page, refetch]
);
useEffect(() => {
// when the epoch changes, we want to refetch the data to update the current page
if (data) {
refetchData();
}
}, [epochId, data, refetchData]);
const epochTotalRewardSummaries =
generateEpochTotalRewardsList({
data,
@@ -65,10 +85,10 @@ export const EpochTotalRewards = ({ currentEpoch }: EpochTotalRewardsProps) => {
isLoading={loading}
hasPrevPage={page > 1}
hasNextPage={page < totalPages}
onBack={() => setPage((x) => x - 1)}
onNext={() => setPage((x) => x + 1)}
onFirst={() => setPage(1)}
onLast={() => setPage(totalPages)}
onBack={() => refetchData(page - 1)}
onNext={() => refetchData(page + 1)}
onFirst={() => refetchData(1)}
onLast={() => refetchData(totalPages)}
>
{t('Page')} {page}
</Pagination>
@@ -149,6 +149,38 @@ describe('generateEpochAssetRewardsList', () => {
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
amount: '0',
},
],
]),
totalAmount: '123',
},
@@ -259,8 +291,40 @@ describe('generateEpochAssetRewardsList', () => {
amount: '100',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
amount: '123',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
amount: '0',
},
],
]),
totalAmount: '100',
totalAmount: '223',
},
],
]),
@@ -270,7 +334,66 @@ describe('generateEpochAssetRewardsList', () => {
'2',
{
epoch: 2,
assetRewards: new Map(),
assetRewards: new Map([
[
'1',
{
assetId: '1',
decimals: 18,
name: 'Asset 1',
rewards: new Map([
[
AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
{
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE,
{
rewardType:
AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '5',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
amount: '0',
},
],
]),
totalAmount: '5',
},
],
]),
},
],
])
@@ -366,7 +489,66 @@ describe('generateEpochAssetRewardsList', () => {
'2',
{
epoch: 2,
assetRewards: new Map(),
assetRewards: new Map([
[
'1',
{
assetId: '1',
name: 'Asset 1',
decimals: 18,
rewards: new Map([
[
AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
{
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE,
{
rewardType:
AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '33',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
amount: '0',
},
],
]),
totalAmount: '33',
},
],
]),
},
],
[
@@ -396,6 +578,38 @@ describe('generateEpochAssetRewardsList', () => {
amount: '15',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
amount: '0',
},
],
]),
totalAmount: '15',
},
@@ -442,8 +656,40 @@ describe('generateEpochAssetRewardsList', () => {
amount: '100',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
amount: '123',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '0',
},
],
[
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
{
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS,
amount: '0',
},
],
]),
totalAmount: '100',
totalAmount: '223',
},
],
]),
@@ -10,7 +10,7 @@ import {
Toggle,
ExternalLink,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import {
useNetworkParams,
NetworkParams,
@@ -18,6 +18,22 @@ export const RowAccountTypes = {
columnTitle: 'rewardsColInfraHeader',
description: 'rewardsColInfraTooltip',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
columnTitle: 'rewardsColPriceTakingHeader',
description: 'rewardsColPriceTakingTooltip',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
columnTitle: 'rewardsColPriceMakingHeader',
description: 'rewardsColPriceMakingTooltip',
},
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
columnTitle: 'rewardsColLiquidityProvisionHeader',
description: 'rewardsColLiquidityProvisionTooltip',
},
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
columnTitle: 'rewardsColMarketCreationHeader',
description: 'rewardsColMarketCreationTooltip',
},
};
interface ColumnHeaderProps {
@@ -39,7 +55,7 @@ export const rowGridItemStyles = (last = false) =>
});
const gridStyles = classNames(
'grid grid-cols-[repeat(4,minmax(100px,auto))] max-w-full overflow-auto',
'grid grid-cols-[repeat(8,minmax(100px,auto))] max-w-full overflow-auto',
`border-t border-vega-dark-200`,
'text-sm'
);
@@ -1,31 +1,27 @@
fragment ValidatorNode on Node {
id
stakedTotal
rewardScore {
rawValidatorScore
performanceScore
multisigScore
validatorScore
normalisedScore
validatorStatus
}
rankingScore {
status
previousStatus
rankingScore
stakeScore
performanceScore
votingPower
}
}
query PreviousEpoch($epochId: ID) {
epoch(id: $epochId) {
id
validatorsConnection {
edges {
node {
...ValidatorNode
id
stakedTotal
rewardScore {
rawValidatorScore
performanceScore
multisigScore
validatorScore
normalisedScore
validatorStatus
}
rankingScore {
status
previousStatus
rankingScore
stakeScore
performanceScore
votingPower
}
}
}
}
@@ -3,8 +3,6 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type ValidatorNodeFragment = { __typename?: 'Node', id: string, stakedTotal: string, rewardScore?: { __typename?: 'RewardScore', rawValidatorScore: string, performanceScore: string, multisigScore: string, validatorScore: string, normalisedScore: string, validatorStatus: Types.ValidatorStatus } | null, rankingScore: { __typename?: 'RankingScore', status: Types.ValidatorStatus, previousStatus: Types.ValidatorStatus, rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string } };
export type PreviousEpochQueryVariables = Types.Exact<{
epochId?: Types.InputMaybe<Types.Scalars['ID']>;
}>;
@@ -12,28 +10,7 @@ export type PreviousEpochQueryVariables = Types.Exact<{
export type PreviousEpochQuery = { __typename?: 'Query', epoch: { __typename?: 'Epoch', id: string, validatorsConnection?: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, stakedTotal: string, rewardScore?: { __typename?: 'RewardScore', rawValidatorScore: string, performanceScore: string, multisigScore: string, validatorScore: string, normalisedScore: string, validatorStatus: Types.ValidatorStatus } | null, rankingScore: { __typename?: 'RankingScore', status: Types.ValidatorStatus, previousStatus: Types.ValidatorStatus, rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string } } } | null> | null } | null } };
export const ValidatorNodeFragmentDoc = gql`
fragment ValidatorNode on Node {
id
stakedTotal
rewardScore {
rawValidatorScore
performanceScore
multisigScore
validatorScore
normalisedScore
validatorStatus
}
rankingScore {
status
previousStatus
rankingScore
stakeScore
performanceScore
votingPower
}
}
`;
export const PreviousEpochDocument = gql`
query PreviousEpoch($epochId: ID) {
epoch(id: $epochId) {
@@ -41,13 +18,30 @@ export const PreviousEpochDocument = gql`
validatorsConnection {
edges {
node {
...ValidatorNode
id
stakedTotal
rewardScore {
rawValidatorScore
performanceScore
multisigScore
validatorScore
normalisedScore
validatorStatus
}
rankingScore {
status
previousStatus
rankingScore
stakeScore
performanceScore
votingPower
}
}
}
}
}
}
${ValidatorNodeFragmentDoc}`;
`;
/**
* __usePreviousEpochQuery__
@@ -33,8 +33,8 @@ let mockVegaWalletHookValue: {
pubKey: null,
};
jest.mock('@vegaprotocol/wallet-react', () => ({
...jest.requireActual('@vegaprotocol/wallet-react'),
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn(() => mockVegaWalletHookValue),
}));
@@ -2,7 +2,7 @@ import { useWeb3React } from '@web3-react/core';
import { useTranslation } from 'react-i18next';
import { EthConnectPrompt } from '../../../../../components/eth-connect-prompt';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { ConnectToVega } from '../../../../../components/connect-to-vega';
export const StakingWalletsContainer = ({
@@ -33,8 +33,8 @@ let mockVegaWalletHookValue: {
pubKey: null,
};
jest.mock('@vegaprotocol/wallet-react', () => ({
...jest.requireActual('@vegaprotocol/wallet-react'),
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn(() => mockVegaWalletHookValue),
}));
@@ -1,4 +1,4 @@
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useWeb3React } from '@web3-react/core';
import { EthConnectPrompt } from '../../../components/eth-connect-prompt';
import { DisassociatePage } from './components/disassociate-page';

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