Compare commits

..
Author SHA1 Message Date
Edd 429a4ca454 feat(explorer): highlight transfer types and add epoch overview 2024-03-04 12:37:54 +00:00
Edd 4d3cd74847 feat(explorer): tests for governancelink 2024-03-04 11:15:25 +00:00
Edd 58ef07adaf feat(explorer): intro on treasury page now has links 2024-03-04 11:15:25 +00:00
Edd ceeb239c3a feat(explorer): intro on treasury page 2024-03-04 11:15:25 +00:00
Edd a5c35b6640 feat(explorer): add epoch by block query and use it in block by id and shareddetails 2024-03-04 11:15:25 +00:00
Matthew Russell 00dbb7dd60 chore(trading): delete trading-e2e cypress tests (#5901) 2024-03-03 14:25:04 +00:00
Matthew Russell 89e2033556 chore(ci): remove unused release script (#5874) 2024-03-01 14:26:43 +00:00
Matthew Russell 2d821700bd fix(trading): check for batch proposal in trading mode tooltip (#5895) 2024-03-01 14:26:29 +00:00
Matthew Russellandbwallacee 28b4593a1d refactor(trading,governance,wallet): wallet rewrite (#5815)
Co-authored-by: bwallacee <ben@vega.xyz>
2024-03-01 14:25:56 +00:00
Matthew Russell 358c734e31 Merge pull request #5893 from vegaprotocol/chore/enable-isolated-margin-testnet
chore(trading): enable isolated margin on testnet
2024-03-01 04:35:00 -05:00
Matthew Russell 3dd7496a9a chore: enable isolated margin on testnet 2024-03-01 09:12:13 +00:00
m.ray 80d576d484 chore(trading): show staking reward cards (#5875) 2024-03-01 06:30:12 +00:00
Matthew Russell 4733bc169c fix(governance): rewards pagination and columns (#5879) 2024-02-29 14:57:07 +00:00
m.ray 2b91aebc2a fix(trading): fees by market fix order (#5877) 2024-02-29 10:25:56 +00:00
m.rayandbwallacee 375f4da541 fix(trading): fix reward card asssets (#5888)
Co-authored-by: bwallacee <ben@vega.xyz>
2024-02-29 09:21:35 +00:00
Matthew Russell bc413ed314 chore(trading): revert reuse vega work (#5883) 2024-02-28 16:57:42 +00:00
BenandMatthew Russell 2fab3daebd chore(trading): update vega binaries (#5873)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2024-02-27 23:24:28 +00:00
Art 2e07ada966 fix(governance): network paramater change in batch proposals (#5869) 2024-02-27 11:47:10 +01:00
ArtandDariusz Majcherczyk b81c4bc948 fix(governance): add multisig score to the validator page (#5845)
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
2024-02-27 11:46:48 +01:00
4f8d6bd876 fix(trading): banner for resume trading (#5849)
Co-authored-by: Art <artur@vegaprotocol.io>
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
2024-02-26 16:17:08 +00:00
Ben 52e5a37da3 chore(trading): fix skipped tests (#5868) 2024-02-26 15:52:22 +00:00
Ben 22599673ec chore(trading): remove fixture usage (#5865) 2024-02-26 14:24:56 +00:00
Ben 3c6a806ad3 chore(trading): reuse vega (#5850) 2024-02-26 12:57:16 +00:00
Dexter Edwards 7101d49d1d chore(governance, trading): update links for new beta extension (#5858) 2024-02-26 12:57:09 +00:00
386 changed files with 5923 additions and 8185 deletions
-36
View File
@@ -1,36 +0,0 @@
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,7 +12,6 @@ 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","trading-e2e"]'
projects: '["explorer-e2e","governance-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 @commitlint/config-conventional @commitlint/config-nx-scopes nx
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
- name: Check PR title
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
run: echo "${{ github.event.pull_request.title }}" | npx @commitlint/cli@16.3.0 --config ./commitlint.config-ci.js
@@ -8,12 +8,14 @@ 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;
};
/**
@@ -24,7 +26,7 @@ export type EpochOverviewProps = {
*
* The details are hidden in a tooltip, behind the epoch number
*/
const EpochOverview = ({ id }: EpochOverviewProps) => {
const EpochOverview = ({ id, icon = true }: EpochOverviewProps) => {
const { data, error, loading } = useExplorerEpochQuery({
variables: { id: id || '' },
});
@@ -38,7 +40,12 @@ const EpochOverview = ({ id }: EpochOverviewProps) => {
}
if (!ti || loading || error) {
return <span>{id}</span>;
return (
<span>
<EpochSymbol />
{id}
</span>
);
}
const description = (
@@ -90,7 +97,11 @@ const EpochOverview = ({ id }: EpochOverviewProps) => {
return (
<Tooltip description={description}>
<p>
<IconForEpoch start={ti.start} end={ti.end} />
{icon ? (
<IconForEpoch start={ti.start} end={ti.end} />
) : (
<EpochSymbol />
)}
{id}
</p>
</Tooltip>
@@ -0,0 +1,10 @@
query ExplorerEpochForBlock($block: String!) {
epoch(block: $block) {
id
timestamps {
start
end
lastBlock
}
}
}
@@ -0,0 +1,53 @@
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,17 +4,56 @@ 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, ...props }: BlockLinkProps) => {
const BlockLink = ({ height, showEpoch = false, ...props }: BlockLinkProps) => {
return (
<Link className="underline" {...props} to={`/${Routes.BLOCKS}/${height}`}>
<Hash text={height} />
</Link>
<>
<Link className="underline" {...props} to={`/${Routes.BLOCKS}/${height}`}>
<Hash text={height} />
</Link>
{showEpoch && <EpochForBlock block={height} />}
</>
);
};
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;
@@ -0,0 +1,16 @@
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();
});
});
@@ -0,0 +1,18 @@
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,6 +10,8 @@ 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;
@@ -44,6 +46,11 @@ 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')}</>;
}
@@ -74,7 +81,7 @@ export const TxDetailsShared = ({
<TableRow modifier="bordered">
<TableCell {...sharedHeaderProps}>{t('Block')}</TableCell>
<TableCell>
<BlockLink height={height} />
<BlockLink height={height} showEpoch={false} />
</TableCell>
</TableRow>
<TableRow modifier="bordered">
@@ -83,6 +90,7 @@ export const TxDetailsShared = ({
<Signature signature={txData.signature} />
</TableCell>
</TableRow>
<TableRow modifier="bordered">
<TableCell {...sharedHeaderProps}>{t('Time')}</TableCell>
<TableCell>
@@ -100,6 +108,14 @@ 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,13 +113,16 @@ export const TxDetailsTransfer = ({
/**
* Gets a string description of this transfer
* @param txData A full transfer
* @param tx 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 top up transfer';
return 'Reward transfer';
}
// Else: we don't know that it's a reward transfer, so let's not guess
} else if (tx.recurring) {
@@ -2,6 +2,7 @@ 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;
@@ -95,7 +96,7 @@ export function getLabelForOrderType(
/**
* Given a proposal, will return a specific label
* @param chainEvent
* @param proposal
* @returns
*/
export function getLabelForProposal(
@@ -142,6 +143,36 @@ 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
@@ -225,9 +256,10 @@ 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 === 'Validator Heartbeat') {
colours =
'text-white dark-text-white bg-vega-light-200 dark:bg-vega-dark-100';
} else if (type === 'Transfer Funds' && command?.transfer) {
const res = getLabelForTransfer(command.transfer);
type = res.type;
colours = res.colours;
} else if (type === 'Proposal' || type === 'Governance Proposal') {
if (command && !!command.proposalSubmission) {
type = getLabelForProposal(command.proposalSubmission);
@@ -16,6 +16,8 @@ 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 };
@@ -26,6 +28,11 @@ 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>
@@ -75,6 +82,7 @@ const Block = () => {
<code>{blockData.result.block.header.consensus_hash}</code>
</TableCell>
</TableRow>
<TableRow modifier="bordered">
<TableHeader scope="row">Mined by</TableHeader>
<TableCell modifier="bordered">
@@ -97,6 +105,14 @@ 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,7 +33,10 @@ 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">
<div
className="basis-1/2 md:basis-1/4"
key={`${a.assetId}-${a.balance}`}
>
<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,19 +16,21 @@ import type { DeepPartial } from '@apollo/client/utilities';
describe('typeLabel', () => {
it('should return "Transfer" for "OneOffTransfer" kind', () => {
expect(typeLabel('OneOffTransfer')).toBe('Transfer');
expect(typeLabel('OneOffTransfer')).toBe('Transfer - one time');
});
it('should return "Transfer" for "RecurringTransfer" kind', () => {
expect(typeLabel('RecurringTransfer')).toBe('Transfer');
expect(typeLabel('RecurringTransfer')).toBe('Transfer - repeating');
});
it('should return "Governance" for "OneOffGovernanceTransfer" kind', () => {
expect(typeLabel('OneOffGovernanceTransfer')).toBe('Governance');
expect(typeLabel('OneOffGovernanceTransfer')).toBe('Governance - one time');
});
it('should return "Governance" for "RecurringGovernanceTransfer" kind', () => {
expect(typeLabel('RecurringGovernanceTransfer')).toBe('Governance');
expect(typeLabel('RecurringGovernanceTransfer')).toBe(
'Governance - repeating'
);
});
it('should return "Unknown" for unknown kind', () => {
@@ -256,7 +258,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'
'Governance - one time'
);
});
});
@@ -12,6 +12,7 @@ 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',
@@ -50,14 +51,24 @@ 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');
return t('Transfer - repeating');
case 'OneOffGovernanceTransfer':
return t('Governance - one time');
case 'RecurringGovernanceTransfer':
return t('Governance');
return t('Governance - repeating');
default:
return t('Unknown');
}
@@ -239,6 +250,11 @@ 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,6 +4,7 @@ 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;
@@ -16,7 +17,33 @@ export const NetworkTreasury = () => {
return (
<section>
<RouteTitle data-testid="block-header">{t(`Treasury`)}</RouteTitle>
<div>
<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">
<NetworkAccountsTable />
</div>
<div className="mt-5">
@@ -34,12 +34,6 @@ 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 })
+1 -2
View File
@@ -14,7 +14,6 @@ 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
@@ -24,7 +23,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/firefox/addon/vega-wallet-fairground
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
#Test configuration variables
CYPRESS_FAIRGROUND=false
+1 -2
View File
@@ -15,12 +15,11 @@ 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/firefox/addon/vega-wallet-fairground
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
+1 -2
View File
@@ -8,14 +8,13 @@ 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/firefox/addon/vega-wallet-fairground
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
-1
View File
@@ -10,7 +10,6 @@ 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,7 +9,6 @@ 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/
+1 -2
View File
@@ -5,7 +5,6 @@ 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/
@@ -13,7 +12,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/firefox/addon/vega-wallet-fairground
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
+1 -2
View File
@@ -9,7 +9,6 @@ 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/
@@ -18,7 +17,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/firefox/addon/vega-wallet-fairground
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
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/firefox/addon/vega-wallet-fairground
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/en-GB/firefox/addon/vega-wallet-beta/
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.
+2 -16
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';
import { useVegaWallet, useEagerConnect } from '@vegaprotocol/wallet-react';
import { useFeatureFlags, useEnvironment } from '@vegaprotocol/environment';
import { useWeb3React } from '@web3-react/core';
import React, { Suspense } from 'react';
@@ -15,20 +15,6 @@ 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);
@@ -40,7 +26,7 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
const { token, staking, vesting } = useContracts();
const setAssociatedBalances = useRefreshAssociatedBalances();
const [balancesLoaded, setBalancesLoaded] = React.useState(false);
const vegaConnecting = useVegaWalletEagerConnect();
const vegaConnecting = useEagerConnect();
const loaded = balancesLoaded && !vegaConnecting;
+31 -141
View File
@@ -1,7 +1,6 @@
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';
@@ -26,7 +25,7 @@ import {
} from '@vegaprotocol/web3';
import { Web3Provider } from '@vegaprotocol/web3';
import { VegaWalletDialogs } from './components/vega-wallet-dialogs';
import { VegaWalletProvider, useChainId } from '@vegaprotocol/wallet';
import { WalletProvider } from '@vegaprotocol/wallet-react';
import {
useVegaTransactionManager,
useVegaTransactionUpdater,
@@ -36,26 +35,21 @@ 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,
TELEMETRY_ON,
} from './components/telemetry-dialog/telemetry-dialog';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
import { TelemetryDialog } from './components/telemetry-dialog/telemetry-dialog';
import { useTranslation } from 'react-i18next';
import { isPartyNotFoundError } from './lib/party';
import { useSentryInit } from './hooks/use-sentry-init';
import { useVegaWalletConfig } from './hooks/use-vega-wallet-config';
const cache: InMemoryCacheConfig = {
typePolicies: {
@@ -104,32 +98,12 @@ 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,
VEGA_ENV,
VEGA_URL,
VEGA_EXPLORER_URL,
CHROME_EXTENSION_URL,
MOZILLA_EXTENSION_URL,
VEGA_WALLET_URL,
} = useEnvironment();
const vegaChainId = useChainId(VEGA_URL);
const { ETHEREUM_PROVIDER_URL, ETH_LOCAL_PROVIDER_URL, ETH_WALLET_MNEMONIC } =
useEnvironment();
useEffect(() => {
if (chainId) {
@@ -150,50 +124,31 @@ const Web3Container = ({
ETH_LOCAL_PROVIDER_URL,
ETH_WALLET_MNEMONIC,
]);
const sideBar = React.useMemo(() => {
return [<EthWallet />, <VegaWallet />];
}, []);
if (connectors.length === 0) {
const vegaWalletConfig = useVegaWalletConfig();
if (!vegaWalletConfig || 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)}>
<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,
},
}}
>
<WalletProvider config={vegaWalletConfig}>
<ContractsProvider>
<AppLoader>
<BalanceManager>
<>
<AppLayout>
<TemplateSidebar sidebar={sideBar}>
<TemplateSidebar
sidebar={
<>
<EthWallet />
<VegaWallet />
</>
}
>
<AppRouter />
</TemplateSidebar>
<footer className="p-4 break-all border-t border-neutral-700">
@@ -211,7 +166,7 @@ const Web3Container = ({
</BalanceManager>
</AppLoader>
</ContractsProvider>
</VegaWalletProvider>
</WalletProvider>
</Web3Connector>
</Web3Provider>
);
@@ -231,20 +186,9 @@ const ScrollToTop = () => {
return null;
};
const removeQueryParams = (url: string) => {
return url.split('?')[0];
};
const AppContainer = () => {
const { config, loading, error } = useEthereumConfig();
const {
VEGA_ENV,
VEGA_URL,
GIT_COMMIT_HASH,
GIT_BRANCH,
ETHEREUM_PROVIDER_URL,
} = useEnvironment();
const [telemetryOn] = useLocalStorage(TELEMETRY_ON);
const { VEGA_URL, ETHEREUM_PROVIDER_URL } = useEnvironment();
const { t } = useTranslation();
const [nodeSwitcherOpen, setNodeSwitcher] = useNodeSwitcherStore((store) => [
store.dialogOpen,
@@ -254,70 +198,7 @@ const AppContainer = () => {
// Hacky skip all the loading & web3 init for geo restricted users
const isRestricted = document?.location?.pathname?.includes('/restricted');
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]);
useSentryInit();
if (isRestricted) {
return (
@@ -359,6 +240,15 @@ 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';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
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,19 +15,16 @@ export const CollapsibleToggle = ({
dataTestId,
children,
}: CollapsibleToggleProps) => {
const classes = classnames(
'mb-4 transition-transform ease-in-out duration-300',
{
'rotate-180': toggleState,
}
);
const classes = classnames('transition-transform ease-in-out duration-300', {
'rotate-180': toggleState,
});
return (
<button
onClick={() => setToggleState(!toggleState)}
data-testid={dataTestId}
>
<div className="flex items-center gap-3">
<div className="flex items-baseline gap-3">
{children}
<div className={classes} data-testid="toggle-icon-wrapper">
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={20} />
@@ -1,18 +1,13 @@
import { Button } from '@vegaprotocol/ui-toolkit';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import { useDialogStore } from '@vegaprotocol/wallet-react';
export const ConnectToVega = () => {
const { t } = useTranslation();
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
const openVegaWalletDialog = useDialogStore((store) => store.open);
return (
<Button
onClick={() => {
openVegaWalletDialog();
}}
onClick={openVegaWalletDialog}
data-testid="connect-to-vega-wallet-btn"
variant="primary"
>
@@ -6,8 +6,8 @@ import {
Intent,
Icon,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '../use-vega-wallet';
import { useT } from '../use-t';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useTranslation } from 'react-i18next';
export interface VegaManageDialogProps {
dialogOpen: boolean;
@@ -18,7 +18,7 @@ export const VegaManageDialog = ({
dialogOpen,
setDialogOpen,
}: VegaManageDialogProps) => {
const t = useT();
const { t } = useTranslation();
const { pubKey, pubKeys, selectPubKey, disconnect } = useVegaWallet();
return (
<Dialog
@@ -1,5 +1,5 @@
import classNames from 'classnames';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import type { ReactNode } from 'react';
import { AnnouncementBanner } from '@vegaprotocol/announcements';
import { Nav } from '../nav';
@@ -1,8 +1,8 @@
import React from 'react';
import { Children, type ReactNode } from 'react';
export interface TemplateSidebarProps {
children: React.ReactNode;
sidebar: React.ReactNode[];
children: ReactNode;
sidebar: 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">
{sidebar.map((Component, i) => (
{Children.map(sidebar, (child, i) => (
<section className="mb-4 last:mb-0" key={i}>
{Component}
{child}
</section>
))}
</aside>
@@ -1,5 +1,5 @@
import { Button } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import { useVegaWallet, useDialogStore } from '@vegaprotocol/wallet-react';
import React from 'react';
import { useTranslation } from 'react-i18next';
@@ -10,9 +10,7 @@ interface VegaWalletContainerProps {
export const VegaWalletContainer = ({ children }: VegaWalletContainerProps) => {
const { t } = useTranslation();
const { pubKey } = useVegaWallet();
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
const openVegaWalletDialog = useDialogStore((store) => store.open);
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 mb-6">
<div className="bg-vega-light-100 dark:bg-vega-dark-100 p-6">
<ul className="list-[square] ml-4">
<li>
{t(
@@ -23,7 +23,7 @@ export const RiskMessage = () => {
</li>
</ul>
</div>
<p className="mb-8">
<p>
{t(
'By using the Vega Governance App, you acknowledge that you have read and understood the'
)}{' '}
@@ -1,25 +1,39 @@
import {
VegaConnectDialog,
VegaManageDialog,
ViewAsDialog,
} from '@vegaprotocol/wallet';
ConnectDialogWithRiskAck,
useDialogStore,
} from '@vegaprotocol/wallet-react';
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 connectors = useConnectors();
const [riskAccepted, setRiskAccepted] = useLocalStorage(
'vega_wallet_risk_accepted'
);
const vegaWalletDialogOpen = useDialogStore((store) => store.isOpen);
const setVegaWalletDialog = useDialogStore((store) => store.set);
return (
<>
<VegaConnectDialog
connectors={connectors}
riskMessage={<RiskMessage />}
<ConnectDialogWithRiskAck
open={vegaWalletDialogOpen}
onChange={setVegaWalletDialog}
riskAccepted={
VEGA_ENV === Networks.TESTNET ? riskAccepted === 'true' : true
}
riskAckContent={<RiskMessage />}
onRiskAccepted={() => setRiskAccepted('true')}
onRiskRejected={() => {
setRiskAccepted('false');
setVegaWalletDialog(false);
}}
/>
<VegaManageDialog
dialogOpen={appState.vegaWalletManageOverlay}
setDialogOpen={(open) =>
@@ -29,8 +43,6 @@ export const VegaWalletDialogs = () => {
})
}
/>
<ViewAsDialog connector={connectors.view} />
</>
);
};
@@ -4,14 +4,13 @@ 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';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useContracts } from '../../contexts/contracts/contracts-context';
import * as Schema from '@vegaprotocol/types';
import {
@@ -37,7 +36,6 @@ export const usePollForDelegations = () => {
const { t } = useTranslation();
const { pubKey } = useVegaWallet();
const client = useApolloClient();
const { delegationsPagination } = ENV;
const [delegations, setDelegations] = React.useState<
WalletDelegationFieldsFragment[]
>([]);
@@ -68,11 +66,9 @@ export const usePollForDelegations = () => {
query: DelegationsDocument,
variables: {
partyId: pubKey,
delegationsPagination: delegationsPagination
? {
first: Number(delegationsPagination),
}
: undefined,
delegationsPagination: {
first: 50,
},
},
fetchPolicy: 'network-only',
})
@@ -236,14 +232,14 @@ export const usePollForDelegations = () => {
// will just continue to fail
clearInterval(interval);
});
}, 1000);
}, 20000);
}
return () => {
clearInterval(interval);
mounted = false;
};
}, [delegationsPagination, client, decimals, pubKey, t, vegaToken.address]);
}, [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 { useViewAsDialog } from '@vegaprotocol/wallet';
import { useConnect } from '@vegaprotocol/wallet-react';
export const VegaWalletPrompt = () => {
const { t } = useTranslation();
const setViewAsDialog = useViewAsDialog((state) => state.setOpen);
const { connect } = useConnect();
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={() => setViewAsDialog(true)}
onClick={() => connect('viewParty')}
>
{t('viewAsParty')}
</ButtonLink>
@@ -25,7 +25,7 @@ import {
} from '../wallet-card';
import { VegaWalletPrompt } from './vega-wallet-prompt';
import { usePollForDelegations } from './hooks';
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import { useVegaWallet, useDialogStore } from '@vegaprotocol/wallet-react';
import { Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
import { toBigNum } from '@vegaprotocol/utils';
import { usePendingBalancesStore } from '../../hooks/use-pending-balances-manager';
@@ -34,16 +34,17 @@ import omit from 'lodash/omit';
export const VegaWallet = () => {
const { t } = useTranslation();
const { pubKey, pubKeys } = useVegaWallet();
const { status, pubKey, pubKeys } = useVegaWallet();
const pubKeyObj = useMemo(() => {
return pubKeys?.find((pk) => pk.publicKey === pubKey);
}, [pubKey, pubKeys]);
const child = !pubKeys ? (
<VegaWalletNotConnected />
) : (
<VegaWalletConnected vegaKeys={pubKeys.map((pk) => pk.publicKey)} />
);
const child =
status === 'connected' ? (
<VegaWalletConnected vegaKeys={pubKeys.map((pk) => pk.publicKey)} />
) : (
<VegaWalletNotConnected />
);
return (
<section className="vega-wallet" data-testid="vega-wallet">
@@ -75,9 +76,7 @@ export const VegaWallet = () => {
const VegaWalletNotConnected = () => {
const { t } = useTranslation();
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
const openVegaWalletDialog = useDialogStore((store) => store.open);
return (
<>
<Button
-1
View File
@@ -65,7 +65,6 @@ 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 | null,
vegaPublicKey: string | undefined,
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';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useEthereumConfig } from '@vegaprotocol/web3';
import React from 'react';
@@ -0,0 +1,81 @@
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];
};
@@ -0,0 +1,41 @@
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'],
ns: ['governance', 'wallet', 'wallet-react'],
defaultNS: 'governance',
keySeparator: false, // we use content as keys
nsSeparator: false,
@@ -20,6 +20,7 @@ describe('getMultisigStatus', () => {
expect(result).toEqual({
multisigStatus: MultisigStatus.noNodes,
showMultisigStatusError: true,
zeroScoreNodes: [],
});
});
@@ -35,6 +36,7 @@ describe('getMultisigStatus', () => {
expect(result).toEqual({
multisigStatus: MultisigStatus.correct,
showMultisigStatusError: false,
zeroScoreNodes: [],
});
});
@@ -50,6 +52,22 @@ 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',
},
],
});
});
@@ -65,6 +83,15 @@ describe('getMultisigStatus', () => {
expect(result).toEqual({
multisigStatus: MultisigStatus.nodeNeedsAdding,
showMultisigStatusError: true,
zeroScoreNodes: [
{
id: '1',
rewardScore: {
multisigScore: '0',
},
stakedTotal: '1000',
},
],
});
});
});
@@ -1,5 +1,8 @@
import { removePaginationWrapper } from '@vegaprotocol/utils';
import type { PreviousEpochQuery } from '../routes/staking/__generated__/PreviousEpoch';
import type {
PreviousEpochQuery,
ValidatorNodeFragment,
} from '../routes/staking/__generated__/PreviousEpoch';
export enum MultisigStatus {
'correct' = 'correct',
@@ -17,12 +20,15 @@ export const getMultisigStatusInfo = (
previousEpochData?.epoch.validatorsConnection?.edges
);
const hasZero = allNodesInPreviousEpoch.some(
(node) => Number(node?.rewardScore?.multisigScore) === 0
);
const hasOne = allNodesInPreviousEpoch.some(
(node) => Number(node?.rewardScore?.multisigScore) === 1
);
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);
if (hasZero && hasOne) {
// If any individual node has 0 it means that node is missing from the multisig and needs to be added
@@ -38,5 +44,6 @@ export const getMultisigStatusInfo = (
return {
showMultisigStatusError: status !== MultisigStatus.correct,
multisigStatus: status,
zeroScoreNodes,
};
};
@@ -1,30 +0,0 @@
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,7 +5,6 @@ import {
ProposalState,
VoteValue,
} from '@vegaprotocol/types';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import {
generateNoVotes,
@@ -16,9 +15,7 @@ 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';
@@ -45,14 +42,12 @@ const renderComponent = (
render(
<AppStateProvider>
<BrowserRouter>
<MockedProvider mocks={[networkParamsQueryMock, ...mocks]}>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposalHeader
proposal={proposal}
isListItem={isListItem}
voteState={voteState}
/>
</VegaWalletContext.Provider>
<MockedProvider mocks={mocks}>
<ProposalHeader
proposal={proposal}
isListItem={isListItem}
voteState={voteState}
/>
</MockedProvider>
</BrowserRouter>
</AppStateProvider>
@@ -160,7 +155,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 />,
lozenge: <Lozenge className="text-xs" />,
}}
/>
);
@@ -312,8 +312,11 @@ const ProposalDetails = ({
{proposal.subProposals.map((p, i) => {
if (!p?.terms) return null;
return (
<li key={i} className="flex gap-3 items-center">
<span className={getIndicatorStyle(i + 1)}>{i + 1}</span>
<li
key={i}
className="grid grid-cols-[40px_minmax(0,1fr)] grid-rows-1 gap-3 items-center"
>
<Indicator indicator={i + 1} />
<span>
<div>{renderDetails(p.terms)}</div>
<SubProposalStateText
@@ -18,7 +18,7 @@ export const ProposalJson = ({ proposal }: { proposal?: unknown }) => {
<SubHeading title={t('proposalJson')} />
</CollapsibleToggle>
{showDetails && <SyntaxHighlighter data={proposal} />}
{showDetails && <SyntaxHighlighter size="smaller" data={proposal} />}
</section>
);
};
@@ -143,14 +143,14 @@ export const ProposalMarketChanges = ({
<SubHeading
title={
<>
{t('UpdateToMarket')}: <MarketName marketId={marketId} />
{t('UpdateToMarket')}: <MarketName marketId={marketId} truncate />
</>
}
/>
</CollapsibleToggle>
{showChanges && (
<div className="mb-6">
<div className="mb-6 bg-vega-cdark-900 p-2 rounded-lg">
<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 after:bg-vega-yellow-400':
'bg-vega-yellow-400 before:bg-vega-yellow-400':
'yellow' === getColour(indicator, max),
'bg-vega-green-400 after:bg-vega-green-400':
'bg-vega-green-400 before:bg-vega-green-400':
'green' === getColour(indicator, max),
'bg-vega-blue-400 after:bg-vega-blue-400':
'bg-vega-blue-400 before:bg-vega-blue-400':
'blue' === getColour(indicator, max),
'bg-vega-purple-400 after:bg-vega-purple-400':
'bg-vega-purple-400 before:bg-vega-purple-400':
'purple' === getColour(indicator, max),
'bg-vega-pink-400 after:bg-vega-pink-400':
'bg-vega-pink-400 before:bg-vega-pink-400':
'pink' === getColour(indicator, max),
'bg-vega-orange-400 after:bg-vega-orange-400':
'bg-vega-orange-400 before:bg-vega-orange-400':
'orange' === getColour(indicator, max),
'bg-vega-red-400 after:bg-vega-red-400':
'bg-vega-red-400 before:bg-vega-red-400':
'red' === getColour(indicator, max),
'bg-vega-clight-600 after:bg-vega-clight-600':
'bg-vega-clight-600 before: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]',
'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-['']"
'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-['']"
);
@@ -0,0 +1,9 @@
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,6 +1,13 @@
import { useMarketInfoQuery } from '@vegaprotocol/markets';
import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
export const MarketName = ({ marketId }: { marketId?: string }) => {
export const MarketName = ({
marketId,
truncate,
}: {
marketId?: string;
truncate?: boolean;
}) => {
const { data } = useMarketInfoQuery({
variables: {
marketId: marketId || '',
@@ -8,7 +15,7 @@ export const MarketName = ({ marketId }: { marketId?: string }) => {
skip: !marketId,
});
return (
<span>{data?.market?.tradableInstrument.instrument.code || marketId}</span>
);
const id = truncate ? truncateMiddle(marketId || '') : marketId;
return <span>{data?.market?.tradableInstrument.instrument.code || id}</span>;
};
@@ -1,3 +1,4 @@
import { Trans, useTranslation } from 'react-i18next';
import { type ProposalTermsFieldsFragment } from '../../__generated__/Proposals';
import { type Proposal, type BatchProposal } from '../../types';
import { ListAsset } from '../list-asset';
@@ -12,8 +13,10 @@ 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,
@@ -26,6 +29,7 @@ export const ProposalChangeDetails = ({
restData: ProposalNode | null;
indicator?: number;
}) => {
const { t } = useTranslation();
let details = null;
switch (terms.change.__typename) {
@@ -108,6 +112,25 @@ 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;
@@ -120,10 +143,12 @@ export const ProposalChangeDetails = ({
}
}
if (indicator != null) {
if (indicator != null && details != null) {
details = (
<div className="flex gap-3 mb-3">
<div className={getIndicatorStyle(indicator)}>{indicator}</div>
<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>{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,45 +24,44 @@ 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('./proposal-change-details', () => ({
ProposalChangeDetails: () => (
<div data-testid="proposal-change-details"></div>
),
jest.mock('../list-asset', () => ({
ListAsset: () => <div data-testid="proposal-list-asset"></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',
};
jest.mock('../vote-details', () => ({
UserVote: () => <div data-testid="user-vote"></div>,
}));
jest.mock('./proposal-change-details', () => ({
ProposalChangeDetails: () => <div data-testid="proposal-change-details" />,
}));
const renderComponent = (proposal: IProposal) => {
render(
return render(
<MemoryRouter>
<MockedProvider>
<VegaWalletProvider config={vegaWalletConfig}>
<Proposal restData={null} proposal={proposal} />
</VegaWalletProvider>
<MockedWalletProvider>
<AppStateProvider>
<Proposal restData={null} proposal={proposal} />
</AppStateProvider>
</MockedWalletProvider>
</MockedProvider>
</MemoryRouter>
);
@@ -23,7 +23,7 @@ export interface ProposalProps {
export const Proposal = ({ proposal, restData }: ProposalProps) => {
const { t } = useTranslation();
const { submit, Dialog, finalizedVote, transaction } = useVoteSubmit();
const { submit, 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">
<div className="mb-4 flex flex-col gap-0">
{proposal.__typename === 'Proposal' ? (
<ProposalChangeDetails
proposal={proposal}
@@ -88,7 +88,6 @@ export const Proposal = ({ proposal, restData }: ProposalProps) => {
<UserVote
proposal={proposal}
submit={submit}
dialog={Dialog}
transaction={transaction}
voteState={voteState}
voteDatetime={voteDatetime}
@@ -1,15 +1,14 @@
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>
<VegaWalletContext.Provider value={mockWalletContext}>
<AppStateProvider>
<ProposalsListItemDetails id={id} />
</VegaWalletContext.Provider>
</AppStateProvider>
</Router>
);
@@ -206,7 +206,7 @@ export const ProposalsList = ({
/>
)}
<section className="-mx-4 p-4 mb-8 bg-vega-dark-100">
<section className="-mx-4 p-4 mb-8 bg-vega-cdark-900 rounded-l-sm">
<SubHeading title={t('openProposals')} />
{sortedProposals.open.length > 0 ||
@@ -1,25 +1,32 @@
import { render, screen } from '@testing-library/react';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { act, render, screen } from '@testing-library/react';
import {
MockedWalletProvider,
mockConfig,
} from '@vegaprotocol/wallet-react/testing';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { ProposalFormSubmit } from './proposal-form-submit';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
const renderComponent = (
context: VegaWalletContextShape,
isSubmitting: boolean
) => {
const renderComponent = (isSubmitting: boolean) => {
render(
<AppStateProvider>
<VegaWalletContext.Provider value={context}>
<MockedWalletProvider>
<AppStateProvider>
<ProposalFormSubmit isSubmitting={isSubmitting} />
</VegaWalletContext.Provider>
</AppStateProvider>
</AppStateProvider>
</MockedWalletProvider>
);
};
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({ pubKey: null } as VegaWalletContextShape, false);
renderComponent(false);
expect(
screen.getByText('Connect your wallet to submit a proposal')
@@ -30,28 +37,22 @@ describe('Proposal Form Submit', () => {
});
it('should display submit button if wallet is connected', () => {
const pubKey = { publicKey: '123456__123456', name: 'test' };
renderComponent(
{
pubKey: pubKey.publicKey,
pubKeys: [pubKey],
} as VegaWalletContextShape,
false
);
mockConfig.store.setState({
pubKey: pubKey.publicKey,
keys: [pubKey],
});
renderComponent(false);
expect(screen.getByTestId('proposal-submit')).toHaveTextContent(
'Submit proposal'
);
});
it('should display submitting button text if wallet is connected and submitting', () => {
const pubKey = { publicKey: '123456__123456', name: 'test' };
renderComponent(
{
pubKey: pubKey.publicKey,
pubKeys: [pubKey],
} as VegaWalletContextShape,
true
);
mockConfig.store.setState({
pubKey: pubKey.publicKey,
keys: [pubKey],
});
renderComponent(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';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
interface ProposalFormSubmitProps {
@@ -1,19 +1,24 @@
import {
VegaTransactionDialog,
getProposalDialogIcon,
getProposalDialogIntent,
useGetProposalDialogTitle,
} from '@vegaprotocol/proposals';
import type { ProposalEventFieldsFragment } from '@vegaprotocol/proposals';
import type { DialogProps } from '@vegaprotocol/proposals';
import type {
ProposalEventFieldsFragment,
VegaTxState,
} from '@vegaprotocol/proposals';
interface ProposalFormTransactionDialogProps {
finalizedProposal: ProposalEventFieldsFragment | null;
TransactionDialog: (props: DialogProps) => JSX.Element;
transaction: VegaTxState;
onChange: (open: boolean) => void;
}
export const ProposalFormTransactionDialog = ({
finalizedProposal,
TransactionDialog,
transaction,
onChange,
}: ProposalFormTransactionDialogProps) => {
const title = useGetProposalDialogTitle(finalizedProposal?.state);
// Render a custom complete UI if the proposal was rejected otherwise
@@ -24,13 +29,16 @@ export const ProposalFormTransactionDialog = ({
return (
<div data-testid="proposal-transaction-dialog">
<TransactionDialog
<VegaTransactionDialog
title={title}
intent={getProposalDialogIntent(finalizedProposal?.state)}
icon={getProposalDialogIcon(finalizedProposal?.state)}
content={{
Complete: completeContent,
}}
transaction={transaction}
isOpen={transaction.dialogOpen}
onChange={onChange}
/>
</div>
);
@@ -1,10 +1,8 @@
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';
@@ -48,9 +46,7 @@ const renderComponent = (
render(
<Router>
<MockedProvider mocks={mocks}>
<VegaWalletContext.Provider value={mockWalletContext}>
<VoteBreakdown proposal={proposal} />
</VegaWalletContext.Provider>
<VoteBreakdown proposal={proposal} />
</MockedProvider>
</Router>
);
@@ -60,6 +56,7 @@ 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,13 +300,11 @@ const VoteBreakdownBatchSubProposal = ({
</>
) : null;
const indicatorElement = indicator && (
<span className={getIndicatorStyle(indicator)}>{indicator}</span>
);
const indicatorElement = indicator && <Indicator indicator={indicator} />;
return (
<div className="mb-6">
<div className="flex items-baseline gap-3 mb-3">
<div className="flex items-center 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';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { VoteValue } from '@vegaprotocol/types';
import { useEffect, useState } from 'react';
import { useUserVoteQuery } from './__generated__/Vote';
@@ -1,20 +1,19 @@
import { useTranslation } from 'react-i18next';
import { Icon, ExternalLink } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
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 DialogProps, type VegaTxState } from '@vegaprotocol/proposals';
import { 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 | null;
transaction: VegaTxState;
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
dialog: (props: DialogProps) => JSX.Element;
voteState: VoteState | null;
voteDatetime: Date | null;
}
@@ -23,7 +22,6 @@ export const UserVote = ({
proposal,
submit,
transaction,
dialog,
voteState,
voteDatetime,
}: UserVoteProps) => {
@@ -56,7 +54,6 @@ export const UserVote = ({
className="flex"
submit={submit}
transaction={transaction}
dialog={dialog}
/>
)
) : (
@@ -2,33 +2,20 @@ 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={null}
TransactionDialog={mockTransactionDialog}
transaction={{
error: null,
txHash: null,
signature: null,
status: VegaTxStatus.Requested,
dialogOpen: true,
}}
/>
);
@@ -39,8 +26,13 @@ describe('VoteTransactionDialog', () => {
render(
<VoteTransactionDialog
voteState={VoteState.Pending}
transaction={null}
TransactionDialog={mockTransactionDialog}
transaction={{
error: null,
txHash: null,
signature: null,
status: VegaTxStatus.Pending,
dialogOpen: true,
}}
/>
);
@@ -51,8 +43,13 @@ describe('VoteTransactionDialog', () => {
render(
<VoteTransactionDialog
voteState={VoteState.Yes} // or any other state other than Requested or Pending
transaction={null}
TransactionDialog={mockTransactionDialog}
transaction={{
error: null,
txHash: null,
signature: null,
status: VegaTxStatus.Complete,
dialogOpen: true,
}}
/>
);
@@ -65,17 +62,18 @@ describe('VoteTransactionDialog', () => {
<VoteTransactionDialog
voteState={VoteState.Failed}
transaction={{
error: { message: 'Custom error test message', name: 'blah' },
error: unknownError(),
txHash: null,
signature: null,
status: VegaTxStatus.Error,
dialogOpen: false,
dialogOpen: true,
}}
TransactionDialog={mockTransactionDialog}
/>
);
expect(screen.getByText('Custom error test message')).toBeInTheDocument();
expect(
screen.getByText(ConnectorErrors.unknown.message)
).toBeInTheDocument();
});
it('renders default error message when voteState is failed and no error message exists on the tx', () => {
@@ -86,10 +84,9 @@ describe('VoteTransactionDialog', () => {
error: null,
txHash: null,
signature: null,
status: VegaTxStatus.Error,
dialogOpen: false,
status: VegaTxStatus.Complete,
dialogOpen: true,
}}
TransactionDialog={mockTransactionDialog}
/>
);
@@ -100,8 +97,13 @@ describe('VoteTransactionDialog', () => {
render(
<VoteTransactionDialog
voteState={VoteState.Yes}
transaction={null}
TransactionDialog={mockTransactionDialog}
transaction={{
error: null,
txHash: null,
signature: null,
status: VegaTxStatus.Default,
dialogOpen: true,
}}
/>
);
@@ -1,120 +1,77 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { act, fireEvent, render, screen } from '@testing-library/react';
import BigNumber from 'bignumber.js';
import { VoteButtons } from './vote-buttons';
import { VoteButtons, type VoteButtonsProps } 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', () => {
it('should render successfully', () => {
const { baseElement } = render(
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(
<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(1)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
transaction={null}
/>
</VegaWalletContext.Provider>
<MockedWalletProvider>
<VoteButtons {...props} {...testProps} />
</MockedWalletProvider>
</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', () => {
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>
);
renderComponent({ proposalState: ProposalState.STATE_PASSED });
expect(screen.getByText('Voting has ended.')).toBeTruthy();
});
it('should provide a connect wallet prompt if no pubkey', () => {
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>
);
mockConfig.reset();
renderComponent();
expect(screen.getByTestId('connect-wallet')).toBeTruthy();
});
it('should tell the user they need tokens if their current stake is 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>
);
renderComponent({ currentStakeAvailable: new BigNumber(0) });
expect(
screen.getByText(
'You need some VEGA tokens to participate in governance.'
@@ -123,26 +80,10 @@ describe('Vote buttons', () => {
});
it('should tell the user of the minimum requirements if they have some, but not enough tokens', () => {
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>
);
renderComponent({
minVoterBalance: '2000000000000000000',
spamProtectionMinTokens: '1000000000000000000',
});
expect(
screen.getByText(
'You must have at least 2 VEGA associated to vote on this proposal'
@@ -151,51 +92,23 @@ 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', () => {
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>
);
renderComponent({
voteState: VoteState.Yes,
minVoterBalance: '2000000000000000000',
spamProtectionMinTokens: '1000000000000000000',
currentStakeAvailable: new BigNumber(10),
});
expect(screen.getByTestId('you-voted')).toBeInTheDocument();
expect(screen.getByTestId('change-vote-button')).toBeInTheDocument();
});
it('should allow you to change your vote', () => {
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>
);
renderComponent({
voteState: VoteState.No,
minVoterBalance: '2000000000000000000',
spamProtectionMinTokens: '1000000000000000000',
currentStakeAvailable: new BigNumber(10),
});
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, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import { useVegaWallet, useDialogStore } from '@vegaprotocol/wallet-react';
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 { DialogProps, VegaTxState } from '@vegaprotocol/proposals';
import type { VegaTxState } from '@vegaprotocol/proposals';
import { filterAcceptableGraphqlErrors } from '../../../../lib/party';
import {
NetworkParams,
@@ -32,8 +32,7 @@ interface VoteButtonsContainerProps {
proposalId: string | null;
proposalState: ProposalState;
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
transaction: VegaTxState | null;
dialog: (props: DialogProps) => JSX.Element;
transaction: VegaTxState;
className?: string;
}
@@ -136,17 +135,16 @@ export const VoteButtonsContainer = (props: VoteButtonsContainerProps) => {
);
};
interface VoteButtonsProps {
export interface VoteButtonsProps {
voteState: VoteState | null;
voteDatetime: Date | null;
proposalId: string | null;
proposalState: ProposalState;
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
transaction: VegaTxState | null;
dialog: (props: DialogProps) => JSX.Element;
proposalId: string | null;
currentStakeAvailable: BigNumber;
minVoterBalance: string | null;
spamProtectionMinTokens: string | null;
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
transaction: VegaTxState;
}
export const VoteButtons = ({
@@ -159,13 +157,10 @@ export const VoteButtons = ({
spamProtectionMinTokens,
submit,
transaction,
dialog: Dialog,
}: VoteButtonsProps) => {
const { t } = useTranslation();
const { pubKey } = useVegaWallet();
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
const openVegaWalletDialog = useDialogStore((store) => store.open);
const [changeVote, setChangeVote] = React.useState(false);
const proposalVotable = useMemo(
() =>
@@ -184,11 +179,7 @@ export const VoteButtons = ({
if (!pubKey) {
return (
<div data-testid="connect-wallet">
<ButtonLink
onClick={() => {
openVegaWalletDialog();
}}
>
<ButtonLink onClick={openVegaWalletDialog}>
{t('connectVegaWallet')}
</ButtonLink>{' '}
{t('toVote')}
@@ -301,11 +292,7 @@ export const VoteButtons = ({
</p>
)
)}
<VoteTransactionDialog
voteState={voteState}
transaction={transaction}
TransactionDialog={Dialog}
/>
<VoteTransactionDialog voteState={voteState} transaction={transaction} />
</>
);
};
@@ -1,11 +1,13 @@
import { t } from '@vegaprotocol/i18n';
import { VoteState } from './use-user-vote';
import type { DialogProps, VegaTxState } from '@vegaprotocol/proposals';
import {
VegaTransactionDialog,
type VegaTxState,
} from '@vegaprotocol/proposals';
interface VoteTransactionDialogProps {
voteState: VoteState;
transaction: VegaTxState | null;
TransactionDialog: (props: DialogProps) => JSX.Element;
transaction: VegaTxState;
}
const dialogTitle = (voteState: VoteState): string | undefined => {
@@ -22,22 +24,23 @@ 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">
<TransactionDialog
<VegaTransactionDialog
title={dialogTitle(voteState)}
transaction={transaction}
content={{
Complete: customMessage,
}}
isOpen={transaction.dialogOpen}
/>
</div>
);
@@ -1,13 +1,12 @@
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'),
@@ -72,18 +71,19 @@ const updateMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
},
};
const renderComponent = () =>
render(
const renderComponent = () => {
return render(
<Router>
<MockedProvider mocks={[updateMarketNetworkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<MockedWalletProvider>
<AppStateProvider>
<ProposeFreeform />
</VegaWalletContext.Provider>
</AppStateProvider>
</AppStateProvider>
</MockedWalletProvider>
</MockedProvider>
</Router>
);
};
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
@@ -51,7 +51,8 @@ export const ProposeFreeform = () => {
watch,
trigger,
} = useForm<FreeformProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const assembleProposal = (fields: FreeformProposalFormFields) => {
const isVoteDeadlineAtMinimum =
@@ -169,7 +170,8 @@ export const ProposeFreeform = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
/>
</form>
</div>
@@ -1,13 +1,12 @@
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'),
@@ -72,26 +71,27 @@ const updateMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
},
};
const renderComponent = () =>
render(
const renderComponent = () => {
return render(
<Router>
<MockedProvider mocks={[updateMarketNetworkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<MockedWalletProvider>
<AppStateProvider>
<ProposeNetworkParameter />
</VegaWalletContext.Provider>
</AppStateProvider>
</AppStateProvider>
</MockedWalletProvider>
</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', async () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
await expect(baseElement).toBeTruthy();
expect(baseElement).toBeTruthy();
});
it('should render the correct title', async () => {
@@ -91,7 +91,8 @@ export const ProposeNetworkParameter = () => {
watch,
trigger,
} = useForm<NetworkParameterProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const selectedParamEntry = params
? Object.entries(params).find(([key]) => key === selectedNetworkParam)
@@ -312,7 +313,8 @@ export const ProposeNetworkParameter = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
/>
</form>
</div>
@@ -1,13 +1,12 @@
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'),
@@ -72,26 +71,27 @@ const newAssetNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
},
};
const renderComponent = () =>
render(
const renderComponent = () => {
return render(
<Router>
<MockedProvider mocks={[newAssetNetworkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<MockedWalletProvider>
<AppStateProvider>
<ProposeNewAsset />
</VegaWalletContext.Provider>
</AppStateProvider>
</AppStateProvider>
</MockedWalletProvider>
</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', async () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
await expect(baseElement).toBeTruthy();
expect(baseElement).toBeTruthy();
});
it('should render the title', async () => {
@@ -64,7 +64,8 @@ export const ProposeNewAsset = () => {
watch,
trigger,
} = useForm<NewAssetProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const assembleProposal = (fields: NewAssetProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
@@ -232,7 +233,8 @@ export const ProposeNewAsset = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
/>
</form>
</div>
@@ -1,13 +1,12 @@
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'),
@@ -72,26 +71,27 @@ const newMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
},
};
const renderComponent = () =>
render(
const renderComponent = () => {
return render(
<Router>
<MockedProvider mocks={[newMarketNetworkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<MockedWalletProvider>
<AppStateProvider>
<ProposeNewMarket />
</VegaWalletContext.Provider>
</AppStateProvider>
</AppStateProvider>
</MockedWalletProvider>
</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', async () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
await expect(baseElement).toBeTruthy();
expect(baseElement).toBeTruthy();
});
it('should render the form components', async () => {
@@ -62,7 +62,8 @@ export const ProposeNewMarket = () => {
watch,
trigger,
} = useForm<NewMarketProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const assembleProposal = (fields: NewMarketProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
@@ -214,7 +215,8 @@ export const ProposeNewMarket = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
/>
</form>
</div>
@@ -3,8 +3,6 @@ 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';
@@ -12,6 +10,11 @@ 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;
@@ -103,23 +106,15 @@ describe('Raw proposal form', () => {
},
delay: 300,
};
const setup = (mockSendTx = jest.fn()) => {
const setup = () => {
return render(
<AppStateProvider>
<MockedProvider
mocks={[rawProposalNetworkParamsQueryMock, mockProposalEvent]}
>
<VegaWalletContext.Provider
value={
{
pubKey,
sendTx: mockSendTx,
links: { explorer: 'explorer' },
} as unknown as VegaWalletContextShape
}
>
<MockedWalletProvider>
<ProposeRaw />
</VegaWalletContext.Provider>
</MockedWalletProvider>
</MockedProvider>
</AppStateProvider>
);
@@ -127,15 +122,22 @@ 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.fn().mockReturnValue(Promise.resolve());
setup(mockSendTx);
const mockSendTx = jest.spyOn(mockConfig, 'sendTransaction');
setup();
expect(await screen.findByTestId('proposal-submit')).toBeTruthy();
await act(async () => {
@@ -162,20 +164,25 @@ describe('Raw proposal form', () => {
});
it('sends the transaction', async () => {
const mockSendTx = jest.fn().mockReturnValue(
new Promise((resolve) => {
setTimeout(
() =>
resolve({
transactionHash: 'tx-hash',
signature:
'cfe592d169f87d0671dd447751036d0dddc165b9c4b65e5a5060e2bbadd1aa726d4cbe9d3c3b327bcb0bff4f83999592619a2493f9bbd251fae99ce7ce766909',
}),
100
);
})
);
setup(mockSendTx);
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();
await act(async () => {
jest.advanceTimersByTime(paramsDelay);
@@ -206,8 +213,12 @@ describe('Raw proposal form', () => {
fireEvent.click(screen.getByTestId('proposal-submit'));
});
expect(mockSendTx).toHaveBeenCalledWith(pubKey, {
proposalSubmission: JSON.parse(inputJSON),
expect(mockSendTx).toHaveBeenCalledWith({
publicKey: pubKey,
sendingMode: 'TYPE_SYNC',
transaction: {
proposalSubmission: JSON.parse(inputJSON),
},
});
expect(screen.getByTestId('dialog-title')).toHaveTextContent(
@@ -232,12 +243,12 @@ describe('Raw proposal form', () => {
});
it('can be rejected by the user', async () => {
const mockSendTx = jest.fn().mockReturnValue(
new Promise((resolve) => {
setTimeout(() => resolve(null), 100);
jest.spyOn(mockConfig, 'sendTransaction').mockReturnValue(
new Promise((_, reject) => {
setTimeout(() => reject(userRejectedError()), 100);
})
);
setup(mockSendTx);
setup();
await act(async () => {
jest.advanceTimersByTime(paramsDelay);
@@ -52,7 +52,8 @@ export const ProposeRaw = () => {
handleSubmit,
formState: { isSubmitting, errors },
} = useForm<RawProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const hasError = Boolean(errors.rawProposalData?.message);
@@ -152,7 +153,8 @@ export const ProposeRaw = () => {
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
/>
</form>
</div>
@@ -1,13 +1,12 @@
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'),
@@ -72,26 +71,27 @@ const updateAssetNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
},
};
const renderComponent = () =>
render(
const renderComponent = () => {
return render(
<Router>
<MockedProvider mocks={[updateAssetNetworkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<MockedWalletProvider>
<AppStateProvider>
<ProposeUpdateAsset />
</VegaWalletContext.Provider>
</AppStateProvider>
</AppStateProvider>
</MockedWalletProvider>
</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', async () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
await expect(baseElement).toBeTruthy();
expect(baseElement).toBeTruthy();
});
it('should render the title', async () => {
@@ -62,7 +62,8 @@ export const ProposeUpdateAsset = () => {
watch,
trigger,
} = useForm<UpdateAssetProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const assembleProposal = (fields: UpdateAssetProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
@@ -218,7 +219,8 @@ export const ProposeUpdateAsset = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
/>
</form>
</div>
@@ -2,15 +2,14 @@ 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: {
@@ -217,29 +216,30 @@ const marketQueryMock: MockedResponse<ProposalMarketsQueryQuery> = {
},
};
const renderComponent = () =>
render(
const renderComponent = () => {
return render(
<MockedProvider
mocks={[updateMarketNetworkParamsQueryMock, marketQueryMock]}
addTypename={false}
>
<Router>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<MockedWalletProvider>
<AppStateProvider>
<ProposeUpdateMarket />
</VegaWalletContext.Provider>
</AppStateProvider>
</AppStateProvider>
</MockedWalletProvider>
</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', async () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
await expect(baseElement).toBeTruthy();
expect(baseElement).toBeTruthy();
});
it('should render the title', async () => {
@@ -109,7 +109,8 @@ export const ProposeUpdateMarket = () => {
watch,
trigger,
} = useForm<UpdateMarketProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const { finalizedProposal, transaction, submit, setTransaction } =
useProposalSubmit();
const assembleProposal = (fields: UpdateMarketProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
@@ -323,7 +324,8 @@ export const ProposeUpdateMarket = () => {
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
transaction={transaction}
onChange={(open) => setTransaction({ dialogOpen: open })}
/>
</form>
</div>
@@ -1,28 +1,17 @@
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: PubKey = {
export const mockPubkey: Key = {
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,13 +1,11 @@
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import { useDialogStore } from '@vegaprotocol/wallet-react';
import { Button } from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../components/heading';
export const ConnectToSeeRewards = () => {
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
const openVegaWalletDialog = useDialogStore((store) => store.open);
const { t } = useTranslation();
const classes = classNames(
@@ -1,11 +1,10 @@
import { useMemo, useEffect, useState, useCallback, useRef } from 'react';
import { useMemo, useState } 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 { ENV } from '../../../config';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { EpochIndividualRewardsTable } from './epoch-individual-rewards-table';
import { generateEpochIndividualRewardsList } from './generate-epoch-individual-rewards-list';
import { calculateEpochOffset } from '../../../lib/epoch-pagination';
@@ -27,22 +26,16 @@ 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, refetch } = useRewardsQuery({
const { data, loading, error } = useRewardsQuery({
notifyOnNetworkStatusChange: true,
variables: {
partyId: pubKey || '',
fromEpoch: epochId - EPOCHS_PAGE_SIZE,
toEpoch: epochId,
delegationsPagination: delegationsPagination
? {
first: Number(delegationsPagination),
}
: undefined,
...calculateEpochOffset({ epochId, page, size: EPOCHS_PAGE_SIZE }),
delegationsPagination: { first: 50 },
},
skip: !pubKey,
});
@@ -70,36 +63,6 @@ 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 || [];
@@ -131,10 +94,10 @@ export const EpochIndividualRewards = ({
isLoading={loading}
hasPrevPage={page > 1}
hasNextPage={page < totalPages}
onBack={() => refetchData(page - 1)}
onNext={() => refetchData(page + 1)}
onFirst={() => refetchData(1)}
onLast={() => refetchData(totalPages)}
onBack={() => setPage((x) => x - 1)}
onNext={() => setPage((x) => x + 1)}
onFirst={() => setPage(1)}
onLast={() => setPage(totalPages)}
>
{t('Page')} {page}
</Pagination>
@@ -23,36 +23,6 @@ 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',
@@ -120,26 +90,10 @@ 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',
},
},
},
],
@@ -147,7 +101,7 @@ describe('generateEpochIndividualRewardsList', () => {
});
it('should return an array sorted by epoch descending', () => {
const rewards = [reward1, reward2, reward3, reward4];
const rewards = [reward1, reward2];
const result1 = generateEpochIndividualRewardsList({
rewards,
epochId: 2,
@@ -157,7 +111,7 @@ describe('generateEpochIndividualRewardsList', () => {
expect(result1[0].epoch).toEqual(2);
expect(result1[1].epoch).toEqual(1);
const reorderedRewards = [reward4, reward3, reward2, reward1];
const reorderedRewards = [reward2, reward1];
const result2 = generateEpochIndividualRewardsList({
rewards: reorderedRewards,
epochId: 2,
@@ -170,7 +124,7 @@ describe('generateEpochIndividualRewardsList', () => {
it('returns data in the expected shape', () => {
// Just sanity checking the whole structure here
const rewards = [reward1, reward2, reward3, reward4];
const rewards = [reward1, reward2];
const result = generateEpochIndividualRewardsList({
rewards,
epochId: 2,
@@ -181,37 +135,6 @@ 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',
@@ -221,26 +144,10 @@ 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',
},
},
},
],
@@ -250,33 +157,17 @@ describe('generateEpochIndividualRewardsList', () => {
rewards: [
{
asset: 'USD',
totalAmount: '200',
totalAmount: '100',
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',
},
},
},
],
@@ -285,7 +176,7 @@ describe('generateEpochIndividualRewardsList', () => {
});
it('returns data correctly for the requested epoch range', () => {
const rewards = [reward1, reward2, reward3, reward4, reward5];
const rewards = [reward1, reward2];
const resultPageOne = generateEpochIndividualRewardsList({
rewards,
epochId: 3,
@@ -297,74 +188,11 @@ describe('generateEpochIndividualRewardsList', () => {
expect(resultPageOne).toEqual([
{
epoch: 3,
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',
},
},
},
],
rewards: [],
},
{
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',
@@ -374,26 +202,10 @@ 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',
},
},
},
],
@@ -414,33 +226,17 @@ describe('generateEpochIndividualRewardsList', () => {
rewards: [
{
asset: 'USD',
totalAmount: '200',
totalAmount: '100',
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, useCallback, useEffect } from 'react';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { AsyncRenderer, Pagination } from '@vegaprotocol/ui-toolkit';
import type { EpochFieldsFragment } from '../home/__generated__/Rewards';
@@ -23,37 +23,17 @@ export const EpochTotalRewards = ({ currentEpoch }: EpochTotalRewardsProps) => {
'rewards_marketCreationQuantumMultiple'
);
const [page, setPage] = useState(1);
const { data, loading, error, refetch } = useEpochAssetsRewardsQuery({
const { data, loading, error } = useEpochAssetsRewardsQuery({
notifyOnNetworkStatusChange: true,
variables: {
epochRewardSummariesFilter: {
fromEpoch: epochId - EPOCHS_PAGE_SIZE,
},
epochRewardSummariesFilter: calculateEpochOffset({
epochId,
page: page,
size: 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,
@@ -85,10 +65,10 @@ export const EpochTotalRewards = ({ currentEpoch }: EpochTotalRewardsProps) => {
isLoading={loading}
hasPrevPage={page > 1}
hasNextPage={page < totalPages}
onBack={() => refetchData(page - 1)}
onNext={() => refetchData(page + 1)}
onFirst={() => refetchData(1)}
onLast={() => refetchData(totalPages)}
onBack={() => setPage((x) => x - 1)}
onNext={() => setPage((x) => x + 1)}
onFirst={() => setPage(1)}
onLast={() => setPage(totalPages)}
>
{t('Page')} {page}
</Pagination>
@@ -149,38 +149,6 @@ 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',
},
@@ -291,40 +259,8 @@ 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: '223',
totalAmount: '100',
},
],
]),
@@ -334,66 +270,7 @@ describe('generateEpochAssetRewardsList', () => {
'2',
{
epoch: 2,
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',
},
],
]),
assetRewards: new Map(),
},
],
])
@@ -489,66 +366,7 @@ describe('generateEpochAssetRewardsList', () => {
'2',
{
epoch: 2,
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',
},
],
]),
assetRewards: new Map(),
},
],
[
@@ -578,38 +396,6 @@ 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',
},
@@ -656,40 +442,8 @@ 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: '223',
totalAmount: '100',
},
],
]),
@@ -10,7 +10,7 @@ import {
Toggle,
ExternalLink,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import {
useNetworkParams,
NetworkParams,
@@ -18,22 +18,6 @@ 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 {
@@ -55,7 +39,7 @@ export const rowGridItemStyles = (last = false) =>
});
const gridStyles = classNames(
'grid grid-cols-[repeat(8,minmax(100px,auto))] max-w-full overflow-auto',
'grid grid-cols-[repeat(4,minmax(100px,auto))] max-w-full overflow-auto',
`border-t border-vega-dark-200`,
'text-sm'
);
@@ -1,27 +1,31 @@
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 {
id
stakedTotal
rewardScore {
rawValidatorScore
performanceScore
multisigScore
validatorScore
normalisedScore
validatorStatus
}
rankingScore {
status
previousStatus
rankingScore
stakeScore
performanceScore
votingPower
}
...ValidatorNode
}
}
}
@@ -3,6 +3,8 @@ 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']>;
}>;
@@ -10,7 +12,28 @@ 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) {
@@ -18,30 +41,13 @@ export const PreviousEpochDocument = gql`
validatorsConnection {
edges {
node {
id
stakedTotal
rewardScore {
rawValidatorScore
performanceScore
multisigScore
validatorScore
normalisedScore
validatorStatus
}
rankingScore {
status
previousStatus
rankingScore
stakeScore
performanceScore
votingPower
}
...ValidatorNode
}
}
}
}
}
`;
${ValidatorNodeFragmentDoc}`;
/**
* __usePreviousEpochQuery__
@@ -33,8 +33,8 @@ let mockVegaWalletHookValue: {
pubKey: null,
};
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
jest.mock('@vegaprotocol/wallet-react', () => ({
...jest.requireActual('@vegaprotocol/wallet-react'),
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';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { ConnectToVega } from '../../../../../components/connect-to-vega';
export const StakingWalletsContainer = ({

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