Compare commits
89 Commits
develop
...
urbit-buil
Author | SHA1 | Date | |
---|---|---|---|
73049215dd | |||
cc782b5eae | |||
|
703792fbda | ||
|
029357b5ab | ||
|
954b4b2755 | ||
|
d238662c9d | ||
|
88251fae4d | ||
|
17946ae149 | ||
|
ebb0db3b37 | ||
|
df21996707 | ||
|
bb2464ddc2 | ||
|
a77bb06b2f | ||
|
1e15032c06 | ||
|
e28cdb2463 | ||
|
840ca63464 | ||
|
64fc075f7a | ||
|
bfa6be4c1c | ||
|
5f8c725c5b | ||
|
6d4d0d548e | ||
|
cd4b0e508e | ||
|
ed9cd3e0dd | ||
|
91d00a0520 | ||
|
0ada3a2f8d | ||
|
2efe0a7aa1 | ||
|
678ba9c4f7 | ||
|
4d566f5a5f | ||
|
f13307aa77 | ||
|
aed45e419d | ||
|
01e87443ee | ||
|
891e0d3d2f | ||
|
dc81334aec | ||
|
0a70c0ea49 | ||
|
05debbd777 | ||
|
8c383d8756 | ||
|
3e61018d89 | ||
|
77b1306f25 | ||
|
ff3cddc21b | ||
|
1d2ca52a25 | ||
|
62ecaaa9ce | ||
|
204871b81c | ||
|
ecdd917977 | ||
|
c0396db2b1 | ||
|
1fd1013353 | ||
|
e389579537 | ||
|
74f0f7bb3d | ||
|
3e78d55c0e | ||
|
1df8ba0972 | ||
|
e515928d87 | ||
|
2928181884 | ||
|
f6f3fb43eb | ||
|
1511772849 | ||
|
ab6c67fd37 | ||
|
f4212724d0 | ||
|
7b162104b6 | ||
|
88f99031d1 | ||
|
72df08851c | ||
|
d9292b9be2 | ||
|
be8de04686 | ||
|
bd14c2a39a | ||
|
8e2ec8ab67 | ||
|
0636d19b0d | ||
|
0dd58b68cf | ||
|
49fdd0f68a | ||
|
3e2e3c3970 | ||
|
b89523efb2 | ||
|
be9a5a3437 | ||
|
475b52bcaf | ||
|
7620f0b67d | ||
|
0f5b712034 | ||
|
424061d64c | ||
|
a49f5f0dd1 | ||
|
bf094288fd | ||
|
bc8a427788 | ||
|
447dc254d7 | ||
|
cebbdb4ee7 | ||
|
fd69f6078c | ||
|
917bdde0bb | ||
|
2153367258 | ||
|
c0942d56a1 | ||
|
e57a6de765 | ||
|
9eee76e5a6 | ||
|
aa71e608f0 | ||
|
20ad18c8a0 | ||
|
457422b5ac | ||
|
990c894e2f | ||
|
2e28a175ce | ||
|
a77858c1c0 | ||
|
05b39e2c08 | ||
|
654dd1e7b0 |
@ -4,6 +4,5 @@ tmp/*
|
|||||||
.dockerignore
|
.dockerignore
|
||||||
dockerfiles
|
dockerfiles
|
||||||
node_modules
|
node_modules
|
||||||
.git
|
|
||||||
.github
|
.github
|
||||||
.vscode
|
.vscode
|
||||||
|
23
.github/workflows/console-test-run.yml
vendored
23
.github/workflows/console-test-run.yml
vendored
@ -10,7 +10,7 @@ on:
|
|||||||
inputs:
|
inputs:
|
||||||
console-test-branch:
|
console-test-branch:
|
||||||
type: choice
|
type: choice
|
||||||
description: 'main: v0.73.13, develop: v0.74.0'
|
description: 'main: v0.74.10, develop: v0.75.5'
|
||||||
options:
|
options:
|
||||||
- main
|
- main
|
||||||
- develop
|
- develop
|
||||||
@ -57,15 +57,14 @@ jobs:
|
|||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Build trading app
|
- name: Build trading app
|
||||||
run: |
|
run: |
|
||||||
yarn env-cmd -f ./apps/trading/.env.stagnet1 yarn nx export trading
|
ENV_NAME="${{ needs.console-test-branch.outputs.console-branch == 'main' && 'mainnet' || 'stagnet1' }}"
|
||||||
|
yarn env-cmd -f ./apps/trading/.env.$ENV_NAME yarn nx export trading
|
||||||
DIST_LOCATION=dist/apps/trading/exported
|
DIST_LOCATION=dist/apps/trading/exported
|
||||||
mv $DIST_LOCATION dist-result
|
mv $DIST_LOCATION dist-result
|
||||||
tree dist-result
|
tree dist-result
|
||||||
|
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# export trading app docker image
|
# export trading app docker image
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
@ -78,7 +77,7 @@ jobs:
|
|||||||
load: true
|
load: true
|
||||||
build-args: |
|
build-args: |
|
||||||
APP=trading
|
APP=trading
|
||||||
ENV_NAME=stagnet1
|
ENV_NAME=${{ needs.console-test-branch.outputs.console-branch == 'main' && 'mainnet' || 'stagnet1' }}
|
||||||
tags: ci/trading:local
|
tags: ci/trading:local
|
||||||
outputs: type=docker,dest=/tmp/console-image.tar
|
outputs: type=docker,dest=/tmp/console-image.tar
|
||||||
|
|
||||||
@ -182,12 +181,22 @@ jobs:
|
|||||||
virtualenvs-create: true
|
virtualenvs-create: true
|
||||||
virtualenvs-in-project: true
|
virtualenvs-in-project: true
|
||||||
virtualenvs-path: .venv
|
virtualenvs-path: .venv
|
||||||
|
#----------------------------------------------
|
||||||
|
# Set up pyproject.toml based on branch
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Create pyproject.toml based on branch
|
||||||
|
run: |
|
||||||
|
if [ "${{ needs.console-test-branch.outputs.console-branch }}" = "main" ]; then
|
||||||
|
mv pyproject.main.toml pyproject.toml
|
||||||
|
elif [ "${{ needs.console-test-branch.outputs.console-branch }}" = "develop" ]; then
|
||||||
|
mv pyproject.develop.toml pyproject.toml
|
||||||
|
fi
|
||||||
|
working-directory: apps/trading/e2e
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# install python dependencies
|
# install python dependencies
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: poetry install --no-interaction --no-root
|
run: poetry lock && poetry install --no-interaction --no-root
|
||||||
working-directory: apps/trading/e2e
|
working-directory: apps/trading/e2e
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# install vega binaries
|
# install vega binaries
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -58,5 +58,6 @@ __pycache__/
|
|||||||
apps/trading/e2e/logs/
|
apps/trading/e2e/logs/
|
||||||
apps/trading/e2e/.pytest_cache/
|
apps/trading/e2e/.pytest_cache/
|
||||||
apps/trading/e2e/traces/
|
apps/trading/e2e/traces/
|
||||||
|
apps/trading/e2e/pyproject.toml
|
||||||
|
|
||||||
.nx/
|
.nx/
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_VEGA_ENV=VALIDATOR_TESTNET
|
NX_VEGA_ENV=VALIDATORS_TESTNET
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
|
||||||
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
||||||
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
||||||
|
@ -8,12 +8,14 @@ import EpochMissingOverview from './epoch-missing';
|
|||||||
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { IconProps } from '@vegaprotocol/ui-toolkit';
|
import type { IconProps } from '@vegaprotocol/ui-toolkit';
|
||||||
import isPast from 'date-fns/isPast';
|
import isPast from 'date-fns/isPast';
|
||||||
|
import { EpochSymbol } from '../links/block-link/block-link';
|
||||||
|
|
||||||
const borderClass =
|
const borderClass =
|
||||||
'border-solid border-2 border-vega-dark-200 border-collapse';
|
'border-solid border-2 border-vega-dark-200 border-collapse';
|
||||||
|
|
||||||
export type EpochOverviewProps = {
|
export type EpochOverviewProps = {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
icon?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,7 +26,7 @@ export type EpochOverviewProps = {
|
|||||||
*
|
*
|
||||||
* The details are hidden in a tooltip, behind the epoch number
|
* 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({
|
const { data, error, loading } = useExplorerEpochQuery({
|
||||||
variables: { id: id || '' },
|
variables: { id: id || '' },
|
||||||
});
|
});
|
||||||
@ -38,7 +40,12 @@ const EpochOverview = ({ id }: EpochOverviewProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ti || loading || error) {
|
if (!ti || loading || error) {
|
||||||
return <span>{id}</span>;
|
return (
|
||||||
|
<span>
|
||||||
|
<EpochSymbol />
|
||||||
|
{id}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const description = (
|
const description = (
|
||||||
@ -90,7 +97,11 @@ const EpochOverview = ({ id }: EpochOverviewProps) => {
|
|||||||
return (
|
return (
|
||||||
<Tooltip description={description}>
|
<Tooltip description={description}>
|
||||||
<p>
|
<p>
|
||||||
<IconForEpoch start={ti.start} end={ti.end} />
|
{icon ? (
|
||||||
|
<IconForEpoch start={ti.start} end={ti.end} />
|
||||||
|
) : (
|
||||||
|
<EpochSymbol />
|
||||||
|
)}
|
||||||
{id}
|
{id}
|
||||||
</p>
|
</p>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
query ExplorerEpochForBlock($block: String!) {
|
||||||
|
epoch(block: $block) {
|
||||||
|
id
|
||||||
|
timestamps {
|
||||||
|
start
|
||||||
|
end
|
||||||
|
lastBlock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
apps/explorer/src/app/components/links/block-link/__generated__/EpochByBlock.ts
generated
Normal file
53
apps/explorer/src/app/components/links/block-link/__generated__/EpochByBlock.ts
generated
Normal file
@ -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 type { ComponentProps } from 'react';
|
||||||
import Hash from '../hash';
|
import Hash from '../hash';
|
||||||
|
import { useExplorerEpochForBlockQuery } from './__generated__/EpochByBlock';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
export type BlockLinkProps = Partial<ComponentProps<typeof Link>> & {
|
export type BlockLinkProps = Partial<ComponentProps<typeof Link>> & {
|
||||||
height: string;
|
height: string;
|
||||||
|
showEpoch?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BlockLink = ({ height, ...props }: BlockLinkProps) => {
|
const BlockLink = ({ height, showEpoch = false, ...props }: BlockLinkProps) => {
|
||||||
return (
|
return (
|
||||||
<Link className="underline" {...props} to={`/${Routes.BLOCKS}/${height}`}>
|
<>
|
||||||
<Hash text={height} />
|
<Link className="underline" {...props} to={`/${Routes.BLOCKS}/${height}`}>
|
||||||
</Link>
|
<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;
|
export default BlockLink;
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import type { ChainIdMapping } from './external-chain';
|
import type { ChainIdMapping } from '@vegaprotocol/environment';
|
||||||
import { SUPPORTED_CHAIN_IDS, SUPPORTED_CHAIN_LABELS } from './external-chain';
|
import {
|
||||||
|
SUPPORTED_CHAIN_IDS,
|
||||||
|
SUPPORTED_CHAIN_LABELS,
|
||||||
|
} from '@vegaprotocol/environment';
|
||||||
|
|
||||||
export const SUPPORTED_CHAIN_ICON_URLS: ChainIdMapping = {
|
export const SUPPORTED_CHAIN_ICON_URLS: ChainIdMapping = {
|
||||||
'1': '/assets/chain-eth-logo.svg',
|
'1': '/assets/chain-eth-logo.svg',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Hash from '../hash';
|
import Hash from '../hash';
|
||||||
import { getExternalExplorerLink } from './external-chain';
|
import { getExternalExplorerLink } from '@vegaprotocol/environment';
|
||||||
import { ExternalChainIcon } from './external-chain-icon';
|
import { ExternalChainIcon } from './external-chain-icon';
|
||||||
|
|
||||||
export enum EthExplorerLinkTypes {
|
export enum EthExplorerLinkTypes {
|
||||||
@ -23,7 +23,7 @@ export const ExternalExplorerLink = ({
|
|||||||
code = false,
|
code = false,
|
||||||
...props
|
...props
|
||||||
}: ExternalExplorerLinkProps) => {
|
}: ExternalExplorerLinkProps) => {
|
||||||
const link = `${getExternalExplorerLink(chain, type)}/${type}/${id}${
|
const link = `${getExternalExplorerLink(chain)}/${type}/${id}${
|
||||||
code ? '#code' : ''
|
code ? '#code' : ''
|
||||||
}`;
|
}`;
|
||||||
return (
|
return (
|
||||||
|
@ -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;
|
@ -6,6 +6,7 @@ import {
|
|||||||
LiquiditySLAParametersInfoPanel,
|
LiquiditySLAParametersInfoPanel,
|
||||||
MarginScalingFactorsPanel,
|
MarginScalingFactorsPanel,
|
||||||
PriceMonitoringBoundsInfoPanel,
|
PriceMonitoringBoundsInfoPanel,
|
||||||
|
PriceMonitoringSettingsInfoPanel,
|
||||||
SuccessionLineInfoPanel,
|
SuccessionLineInfoPanel,
|
||||||
getDataSourceSpecForSettlementData,
|
getDataSourceSpecForSettlementData,
|
||||||
getDataSourceSpecForTradingTermination,
|
getDataSourceSpecForTradingTermination,
|
||||||
@ -21,7 +22,6 @@ import {
|
|||||||
RiskModelInfoPanel,
|
RiskModelInfoPanel,
|
||||||
SettlementAssetInfoPanel,
|
SettlementAssetInfoPanel,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import { MarketInfoTable } from '@vegaprotocol/markets';
|
|
||||||
import type { DataSourceFragment } from '@vegaprotocol/markets';
|
import type { DataSourceFragment } from '@vegaprotocol/markets';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
|
||||||
@ -74,27 +74,14 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
<MarginScalingFactorsPanel market={market} />
|
<MarginScalingFactorsPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Risk factors')}</h2>
|
<h2 className={headerClassName}>{t('Risk factors')}</h2>
|
||||||
<RiskFactorsInfoPanel market={market} />
|
<RiskFactorsInfoPanel market={market} />
|
||||||
{(market.data?.priceMonitoringBounds || []).map((trigger, i) => (
|
<h2 className={headerClassName}>{t('Price monitoring bounds')}</h2>
|
||||||
<>
|
<div className="mt-3">
|
||||||
<h2 className={headerClassName}>
|
<PriceMonitoringBoundsInfoPanel market={market} />
|
||||||
{t('Price monitoring bounds %s', [(i + 1).toString()])}
|
</div>
|
||||||
</h2>
|
<h2 className={headerClassName}>{t('Price monitoring settings')}</h2>
|
||||||
<PriceMonitoringBoundsInfoPanel
|
<div className="mt-3">
|
||||||
market={market}
|
<PriceMonitoringSettingsInfoPanel market={market} />
|
||||||
triggerIndex={i + 1}
|
</div>
|
||||||
/>
|
|
||||||
</>
|
|
||||||
))}
|
|
||||||
{(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
|
||||||
(trigger, i) => (
|
|
||||||
<>
|
|
||||||
<h2 className={headerClassName}>
|
|
||||||
{t('Price monitoring settings %s', [(i + 1).toString()])}
|
|
||||||
</h2>
|
|
||||||
<MarketInfoTable data={trigger} key={i} />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
<h2 className={headerClassName}>{t('Liquidation strategy')}</h2>
|
<h2 className={headerClassName}>{t('Liquidation strategy')}</h2>
|
||||||
<LiquidationStrategyInfoPanel market={market} />
|
<LiquidationStrategyInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { getAsset, type MarketFieldsFragment } from '@vegaprotocol/markets';
|
import { getAsset, type MarketMaybeWithData } from '@vegaprotocol/markets';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { type AgGridReact } from 'ag-grid-react';
|
import { type AgGridReact } from 'ag-grid-react';
|
||||||
@ -17,7 +17,7 @@ import { type RowClickedEvent } from 'ag-grid-community';
|
|||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
type MarketsTableProps = {
|
type MarketsTableProps = {
|
||||||
data: MarketFieldsFragment[] | null;
|
data: MarketMaybeWithData[] | null;
|
||||||
};
|
};
|
||||||
export const MarketsTable = ({ data }: MarketsTableProps) => {
|
export const MarketsTable = ({ data }: MarketsTableProps) => {
|
||||||
const openAssetDetailsDialog = useAssetDetailsDialogStore(
|
const openAssetDetailsDialog = useAssetDetailsDialogStore(
|
||||||
@ -56,10 +56,10 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
headerName: t('Status'),
|
headerName: t('Status'),
|
||||||
field: 'state',
|
field: 'state',
|
||||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||||
valueGetter: ({
|
valueGetter: ({ data }: VegaValueGetterParams<MarketMaybeWithData>) => {
|
||||||
data,
|
return data?.data?.marketState
|
||||||
}: VegaValueGetterParams<MarketFieldsFragment>) => {
|
? MarketStateMapping[data?.data.marketState]
|
||||||
return data?.state ? MarketStateMapping[data?.state] : '-';
|
: '-';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -70,7 +70,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
cellRenderer: ({
|
cellRenderer: ({
|
||||||
data,
|
data,
|
||||||
}: VegaICellRendererParams<
|
}: VegaICellRendererParams<
|
||||||
MarketFieldsFragment,
|
MarketMaybeWithData,
|
||||||
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
||||||
>) => {
|
>) => {
|
||||||
const value = data && getAsset(data);
|
const value = data && getAsset(data);
|
||||||
@ -99,7 +99,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
field: 'id',
|
field: 'id',
|
||||||
cellRenderer: ({
|
cellRenderer: ({
|
||||||
value,
|
value,
|
||||||
}: VegaICellRendererParams<MarketFieldsFragment, 'id'>) =>
|
}: VegaICellRendererParams<MarketMaybeWithData, 'id'>) =>
|
||||||
value ? (
|
value ? (
|
||||||
<Link className="underline" to={value}>
|
<Link className="underline" to={value}>
|
||||||
{t('View details')}
|
{t('View details')}
|
||||||
@ -116,7 +116,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
<AgGrid
|
<AgGrid
|
||||||
ref={gridRef}
|
ref={gridRef}
|
||||||
rowData={data}
|
rowData={data}
|
||||||
getRowId={({ data }: { data: MarketFieldsFragment }) => data.id}
|
getRowId={({ data }: { data: MarketMaybeWithData }) => data.id}
|
||||||
overlayNoRowsTemplate={t('This chain has no markets')}
|
overlayNoRowsTemplate={t('This chain has no markets')}
|
||||||
domLayout="autoHeight"
|
domLayout="autoHeight"
|
||||||
defaultColDef={{
|
defaultColDef={{
|
||||||
|
159
apps/explorer/src/app/components/oracle-table/index.tsx
Normal file
159
apps/explorer/src/app/components/oracle-table/index.tsx
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
import compact from 'lodash/compact';
|
||||||
|
import { MarketLink } from '../links';
|
||||||
|
import { type MarketState, MarketStateMapping } from '@vegaprotocol/types';
|
||||||
|
import OracleLink from '../links/oracle-link/oracle-link';
|
||||||
|
import type {
|
||||||
|
ExplorerOracleForMarketQuery,
|
||||||
|
ExplorerOracleFormMarketsQuery,
|
||||||
|
} from '../../routes/oracles/__generated__/OraclesForMarkets';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
export type OraclesTableProps = {
|
||||||
|
data?: ExplorerOracleFormMarketsQuery | ExplorerOracleForMarketQuery;
|
||||||
|
};
|
||||||
|
|
||||||
|
const cellSpacing = 'px-3';
|
||||||
|
|
||||||
|
export function OraclesTable({ data }: OraclesTableProps) {
|
||||||
|
const [hoveredOracle, setHoveredOracle] = useState('');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table className="text-left">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th className={cellSpacing}>Market</th>
|
||||||
|
<th className={cellSpacing}>Type</th>
|
||||||
|
<th className={cellSpacing}>State</th>
|
||||||
|
<th className={cellSpacing}>Settlement</th>
|
||||||
|
<th className={cellSpacing}>Termination</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{data?.marketsConnection?.edges
|
||||||
|
? data.marketsConnection.edges.map((o) => {
|
||||||
|
let hasSeenOracleReports = false;
|
||||||
|
let settlementOracle = '-';
|
||||||
|
let settlementOracleStatus = '-';
|
||||||
|
let terminationOracle = '-';
|
||||||
|
let terminationOracleStatus = '-';
|
||||||
|
|
||||||
|
const id = o?.node.id;
|
||||||
|
if (!id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
o.node.tradableInstrument.instrument.product.__typename ===
|
||||||
|
'Future'
|
||||||
|
) {
|
||||||
|
settlementOracle =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementData.id;
|
||||||
|
terminationOracle =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForTradingTermination.id;
|
||||||
|
settlementOracleStatus =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementData.status;
|
||||||
|
terminationOracleStatus =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForTradingTermination.status;
|
||||||
|
} else if (
|
||||||
|
o.node.tradableInstrument.instrument.product.__typename ===
|
||||||
|
'Perpetual'
|
||||||
|
) {
|
||||||
|
settlementOracle =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementData.id;
|
||||||
|
terminationOracle =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementSchedule.id;
|
||||||
|
settlementOracleStatus =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementData.status;
|
||||||
|
terminationOracleStatus =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementSchedule.status;
|
||||||
|
}
|
||||||
|
const oracleInformationUnfiltered =
|
||||||
|
data?.oracleSpecsConnection?.edges?.map((e) =>
|
||||||
|
e && e.node ? e.node : undefined
|
||||||
|
) || [];
|
||||||
|
|
||||||
|
const oracleInformation = compact(oracleInformationUnfiltered)
|
||||||
|
.filter(
|
||||||
|
(o) =>
|
||||||
|
o.dataConnection.edges &&
|
||||||
|
o.dataConnection.edges.length > 0 &&
|
||||||
|
(o.dataSourceSpec.spec.id === settlementOracle ||
|
||||||
|
o.dataSourceSpec.spec.id === terminationOracle)
|
||||||
|
)
|
||||||
|
.at(0);
|
||||||
|
if (oracleInformation) {
|
||||||
|
hasSeenOracleReports = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oracleList = `${settlementOracle} ${terminationOracle}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr
|
||||||
|
id={id}
|
||||||
|
key={id}
|
||||||
|
className={
|
||||||
|
hoveredOracle.length > 0 &&
|
||||||
|
oracleList.indexOf(hoveredOracle) > -1
|
||||||
|
? 'bg-gray-100 dark:bg-gray-800'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
data-testid="oracle-details"
|
||||||
|
data-oracles={oracleList}
|
||||||
|
>
|
||||||
|
<td className={cellSpacing}>
|
||||||
|
<MarketLink id={id} />
|
||||||
|
</td>
|
||||||
|
<td className={cellSpacing}>
|
||||||
|
{o.node.tradableInstrument.instrument.product.__typename}
|
||||||
|
</td>
|
||||||
|
<td className={cellSpacing}>
|
||||||
|
{MarketStateMapping[o.node.state as MarketState]}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
className={
|
||||||
|
hoveredOracle.length > 0 &&
|
||||||
|
hoveredOracle === settlementOracle
|
||||||
|
? `indent-1 ${cellSpacing}`
|
||||||
|
: cellSpacing
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<OracleLink
|
||||||
|
id={settlementOracle}
|
||||||
|
status={settlementOracleStatus}
|
||||||
|
hasSeenOracleReports={hasSeenOracleReports}
|
||||||
|
onMouseOver={() => setHoveredOracle(settlementOracle)}
|
||||||
|
onMouseOut={() => setHoveredOracle('')}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
className={
|
||||||
|
hoveredOracle.length > 0 &&
|
||||||
|
hoveredOracle === terminationOracle
|
||||||
|
? `indent-1 ${cellSpacing}`
|
||||||
|
: cellSpacing
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<OracleLink
|
||||||
|
id={terminationOracle}
|
||||||
|
status={terminationOracleStatus}
|
||||||
|
hasSeenOracleReports={hasSeenOracleReports}
|
||||||
|
onMouseOver={() => setHoveredOracle(terminationOracle)}
|
||||||
|
onMouseOut={() => setHoveredOracle('')}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: null}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
@ -33,10 +33,10 @@ const SizeInAsset = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p>
|
<span>
|
||||||
<span>{label}</span>
|
<span>{label}</span>
|
||||||
<AssetLink assetId={assetId} showAssetSymbol={true} asDialog={true} />
|
<AssetLink assetId={assetId} showAssetSymbol={true} asDialog={true} />
|
||||||
</p>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
ExternalExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/external-explorer-link/external-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
import { getExternalChainLabel } from '../../../links/external-explorer-link/external-chain';
|
import { getExternalChainLabel } from '@vegaprotocol/environment';
|
||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
|
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
|
||||||
import { BigNumber } from 'ethers';
|
import { BigNumber } from 'ethers';
|
||||||
|
@ -10,6 +10,8 @@ import { ChainResponseCode } from '../chain-response-code/chain-reponse.code';
|
|||||||
import { TxDataView } from '../../tx-data-view';
|
import { TxDataView } from '../../tx-data-view';
|
||||||
import Hash from '../../../links/hash';
|
import Hash from '../../../links/hash';
|
||||||
import { Signature } from '../../../signature/signature';
|
import { Signature } from '../../../signature/signature';
|
||||||
|
import { useExplorerEpochForBlockQuery } from '../../../links/block-link/__generated__/EpochByBlock';
|
||||||
|
import EpochOverview from '../../../epoch-overview/epoch';
|
||||||
|
|
||||||
interface TxDetailsSharedProps {
|
interface TxDetailsSharedProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@ -44,6 +46,11 @@ export const TxDetailsShared = ({
|
|||||||
blockData,
|
blockData,
|
||||||
hideTypeRow = false,
|
hideTypeRow = false,
|
||||||
}: TxDetailsSharedProps) => {
|
}: TxDetailsSharedProps) => {
|
||||||
|
const { data } = useExplorerEpochForBlockQuery({
|
||||||
|
errorPolicy: 'ignore',
|
||||||
|
variables: { block: txData?.block?.toString() || '' },
|
||||||
|
});
|
||||||
|
|
||||||
if (!txData) {
|
if (!txData) {
|
||||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
}
|
}
|
||||||
@ -74,7 +81,7 @@ export const TxDetailsShared = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell {...sharedHeaderProps}>{t('Block')}</TableCell>
|
<TableCell {...sharedHeaderProps}>{t('Block')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<BlockLink height={height} />
|
<BlockLink height={height} showEpoch={false} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
@ -83,6 +90,7 @@ export const TxDetailsShared = ({
|
|||||||
<Signature signature={txData.signature} />
|
<Signature signature={txData.signature} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell {...sharedHeaderProps}>{t('Time')}</TableCell>
|
<TableCell {...sharedHeaderProps}>{t('Time')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
@ -100,6 +108,14 @@ export const TxDetailsShared = ({
|
|||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</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">
|
<TableRow modifier="bordered">
|
||||||
<TableCell {...sharedHeaderProps}>{t('Response code')}</TableCell>
|
<TableCell {...sharedHeaderProps}>{t('Response code')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
query ExplorerTransferStatus($id: ID!) {
|
query ExplorerTransferStatus($id: ID!) {
|
||||||
transfer(id: $id) {
|
transfer(id: $id) {
|
||||||
|
fees {
|
||||||
|
amount
|
||||||
|
epoch
|
||||||
|
}
|
||||||
transfer {
|
transfer {
|
||||||
reference
|
reference
|
||||||
timestamp
|
timestamp
|
||||||
|
@ -8,12 +8,16 @@ export type ExplorerTransferStatusQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerTransferStatusQuery = { __typename?: 'Query', transfer?: { __typename?: 'TransferNode', transfer: { __typename?: 'Transfer', reference?: string | null, timestamp: any, status: Types.TransferStatus, reason?: string | null, fromAccountType: Types.AccountType, from: string, to: string, toAccountType: Types.AccountType, amount: string, asset?: { __typename?: 'Asset', id: string } | null } } | null };
|
export type ExplorerTransferStatusQuery = { __typename?: 'Query', transfer?: { __typename?: 'TransferNode', fees?: Array<{ __typename?: 'TransferFee', amount: string, epoch: number } | null> | null, transfer: { __typename?: 'Transfer', reference?: string | null, timestamp: any, status: Types.TransferStatus, reason?: string | null, fromAccountType: Types.AccountType, from: string, to: string, toAccountType: Types.AccountType, amount: string, asset?: { __typename?: 'Asset', id: string } | null } } | null };
|
||||||
|
|
||||||
|
|
||||||
export const ExplorerTransferStatusDocument = gql`
|
export const ExplorerTransferStatusDocument = gql`
|
||||||
query ExplorerTransferStatus($id: ID!) {
|
query ExplorerTransferStatus($id: ID!) {
|
||||||
transfer(id: $id) {
|
transfer(id: $id) {
|
||||||
|
fees {
|
||||||
|
amount
|
||||||
|
epoch
|
||||||
|
}
|
||||||
transfer {
|
transfer {
|
||||||
reference
|
reference
|
||||||
timestamp
|
timestamp
|
||||||
|
@ -44,8 +44,14 @@ const AccountType: Record<AccountTypes, string> = {
|
|||||||
ACCOUNT_TYPE_ORDER_MARGIN: 'Order Margin',
|
ACCOUNT_TYPE_ORDER_MARGIN: 'Order Margin',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TransferFee = {
|
||||||
|
amount?: string;
|
||||||
|
epoch?: number;
|
||||||
|
};
|
||||||
|
|
||||||
interface TransferParticipantsProps {
|
interface TransferParticipantsProps {
|
||||||
transfer: Transfer;
|
transfer: Transfer;
|
||||||
|
fees?: TransferFee[] | null;
|
||||||
from: string;
|
from: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +66,7 @@ interface TransferParticipantsProps {
|
|||||||
export function TransferParticipants({
|
export function TransferParticipants({
|
||||||
transfer,
|
transfer,
|
||||||
from,
|
from,
|
||||||
|
fees,
|
||||||
}: TransferParticipantsProps) {
|
}: TransferParticipantsProps) {
|
||||||
// This mapping is required as the global account types require a type to be set, while
|
// This mapping is required as the global account types require a type to be set, while
|
||||||
// the underlying protobufs allow for every field to be undefined.
|
// the underlying protobufs allow for every field to be undefined.
|
||||||
@ -104,6 +111,9 @@ export function TransferParticipants({
|
|||||||
{transfer.asset ? (
|
{transfer.asset ? (
|
||||||
<SizeInAsset assetId={transfer.asset} size={transfer.amount} />
|
<SizeInAsset assetId={transfer.asset} size={transfer.amount} />
|
||||||
) : null}
|
) : null}
|
||||||
|
{transfer.asset && fees && (
|
||||||
|
<TransferFees assetId={transfer.asset} fees={fees} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Empty divs for the top arrow and the bottom arrow of the transfer inset */}
|
{/* Empty divs for the top arrow and the bottom arrow of the transfer inset */}
|
||||||
@ -125,10 +135,6 @@ export function TransferParticipants({
|
|||||||
<path d="M0,0L8,9l8,-9Z" />
|
<path d="M0,0L8,9l8,-9Z" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
{/*
|
|
||||||
<div className="z-10 absolute top-0 left-1/2 transform -translate-x-1/2 -translate-y-1/2 rotate-45 w-4 h-4 dark:border-vega-dark-200 border-vega-light-200 bg-white dark:bg-black border-r border-b"></div>
|
|
||||||
<div className="z-10 absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-1/2 rotate-45 w-4 h-4 border-vega-light-200 dark:border-vega-dark-200 bg-vega-light-200 dark:bg-vega-dark-200 border-r border-b"></div>
|
|
||||||
*/}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -169,3 +175,38 @@ export function TransferRecurringRecipient({
|
|||||||
// Fallback should not happen
|
// Fallback should not happen
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function TransferFees({
|
||||||
|
assetId,
|
||||||
|
fees,
|
||||||
|
}: {
|
||||||
|
assetId: string;
|
||||||
|
fees: TransferFee[];
|
||||||
|
}) {
|
||||||
|
// A recurring transfer that is rejected or cancelled will have an array of fees of 0 length
|
||||||
|
if (assetId && fees && fees.length > 0) {
|
||||||
|
if (fees.length === 1) {
|
||||||
|
return (
|
||||||
|
<p className="mt-2">
|
||||||
|
Fee: <SizeInAsset assetId={assetId} size={fees[0].amount} />
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<details className="cursor-pointer mt-2">
|
||||||
|
<summary>{t('Fees')}</summary>
|
||||||
|
<ul>
|
||||||
|
{fees.map((fee) => (
|
||||||
|
<li className="text-nowrap leading-normal">
|
||||||
|
<SizeInAsset assetId={assetId} size={fee.amount} />{' '}
|
||||||
|
{t('in epoch')} {fee.epoch}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@ -41,9 +41,16 @@ export function TransferDetails({ transfer, from, id }: TransferDetailsProps) {
|
|||||||
? TransferStatus.STATUS_REJECTED
|
? TransferStatus.STATUS_REJECTED
|
||||||
: data?.transfer?.transfer.status;
|
: data?.transfer?.transfer.status;
|
||||||
|
|
||||||
|
const fees = data?.transfer?.fees?.map((fee) => {
|
||||||
|
return {
|
||||||
|
amount: fee?.amount ? fee.amount : '0',
|
||||||
|
epoch: fee?.epoch ? fee.epoch : 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap">
|
<div className="flex flex-wrap">
|
||||||
<TransferParticipants from={from} transfer={transfer} />
|
<TransferParticipants from={from} transfer={transfer} fees={fees} />
|
||||||
{recurring ? <TransferRepeat recurring={transfer.recurring} /> : null}
|
{recurring ? <TransferRepeat recurring={transfer.recurring} /> : null}
|
||||||
<TransferStatusView status={status} error={error} loading={loading} />
|
<TransferStatusView status={status} error={error} loading={loading} />
|
||||||
{recurring && recurring.dispatchStrategy ? (
|
{recurring && recurring.dispatchStrategy ? (
|
||||||
|
@ -113,13 +113,16 @@ export const TxDetailsTransfer = ({
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a string description of this transfer
|
* Gets a string description of this transfer
|
||||||
* @param txData A full transfer
|
* @param tx A full transfer
|
||||||
* @returns string Transfer label
|
* @returns string Transfer label
|
||||||
*/
|
*/
|
||||||
export function getTypeLabelForTransfer(tx: Transfer) {
|
export function getTypeLabelForTransfer(tx: Transfer) {
|
||||||
if (tx.to === SPECIAL_CASE_NETWORK || tx.to === SPECIAL_CASE_NETWORK_ID) {
|
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) {
|
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: we don't know that it's a reward transfer, so let's not guess
|
||||||
} else if (tx.recurring) {
|
} else if (tx.recurring) {
|
||||||
|
@ -16,12 +16,12 @@ import { FilterLabel } from './tx-filter-label';
|
|||||||
|
|
||||||
// All possible transaction types. Should be generated.
|
// All possible transaction types. Should be generated.
|
||||||
export type FilterOption =
|
export type FilterOption =
|
||||||
| 'Amend LiquidityProvision Order'
|
| 'Amend Liquidity Provision Order'
|
||||||
| 'Amend Order'
|
| 'Amend Order'
|
||||||
| 'Apply Referral Code'
|
| 'Apply Referral Code'
|
||||||
| 'Batch Market Instructions'
|
| 'Batch Market Instructions'
|
||||||
| 'Batch Proposal'
|
| 'Batch Proposal'
|
||||||
| 'Cancel LiquidityProvision Order'
|
| 'Cancel Liquidity Provision Order'
|
||||||
| 'Cancel Order'
|
| 'Cancel Order'
|
||||||
| 'Cancel Transfer Funds'
|
| 'Cancel Transfer Funds'
|
||||||
| 'Chain Event'
|
| 'Chain Event'
|
||||||
@ -53,10 +53,10 @@ export type FilterOption =
|
|||||||
|
|
||||||
export const filterOptions: Record<string, FilterOption[]> = {
|
export const filterOptions: Record<string, FilterOption[]> = {
|
||||||
'Market Instructions': [
|
'Market Instructions': [
|
||||||
'Amend LiquidityProvision Order',
|
'Amend Liquidity Provision Order',
|
||||||
'Amend Order',
|
'Amend Order',
|
||||||
'Batch Market Instructions',
|
'Batch Market Instructions',
|
||||||
'Cancel LiquidityProvision Order',
|
'Cancel Liquidity Provision Order',
|
||||||
'Cancel Order',
|
'Cancel Order',
|
||||||
'Liquidity Provision Order',
|
'Liquidity Provision Order',
|
||||||
'Stop Orders Submission',
|
'Stop Orders Submission',
|
||||||
|
@ -2,6 +2,7 @@ import { t } from '@vegaprotocol/i18n';
|
|||||||
import type { components } from '../../../types/explorer';
|
import type { components } from '../../../types/explorer';
|
||||||
import { VoteIcon } from '../vote-icon/vote-icon';
|
import { VoteIcon } from '../vote-icon/vote-icon';
|
||||||
import { ExternalChainIcon } from '../links/external-explorer-link/external-chain-icon';
|
import { ExternalChainIcon } from '../links/external-explorer-link/external-chain-icon';
|
||||||
|
import { getTypeLabelForTransfer } from './details/tx-transfer';
|
||||||
|
|
||||||
interface TxOrderTypeProps {
|
interface TxOrderTypeProps {
|
||||||
orderType: string;
|
orderType: string;
|
||||||
@ -95,7 +96,7 @@ export function getLabelForOrderType(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a proposal, will return a specific label
|
* Given a proposal, will return a specific label
|
||||||
* @param chainEvent
|
* @param proposal
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getLabelForProposal(
|
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
|
* Given a chain event, will try to provide a more useful label
|
||||||
* @param chainEvent
|
* @param chainEvent
|
||||||
@ -225,9 +256,10 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
|||||||
if (type === 'Chain Event' && !!command?.chainEvent) {
|
if (type === 'Chain Event' && !!command?.chainEvent) {
|
||||||
type = getLabelForChainEvent(command.chainEvent);
|
type = getLabelForChainEvent(command.chainEvent);
|
||||||
colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink';
|
colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink';
|
||||||
} else if (type === 'Validator Heartbeat') {
|
} else if (type === 'Transfer Funds' && command?.transfer) {
|
||||||
colours =
|
const res = getLabelForTransfer(command.transfer);
|
||||||
'text-white dark-text-white bg-vega-light-200 dark:bg-vega-dark-100';
|
type = res.type;
|
||||||
|
colours = res.colours;
|
||||||
} else if (type === 'Proposal' || type === 'Governance Proposal') {
|
} else if (type === 'Proposal' || type === 'Governance Proposal') {
|
||||||
if (command && !!command.proposalSubmission) {
|
if (command && !!command.proposalSubmission) {
|
||||||
type = getLabelForProposal(command.proposalSubmission);
|
type = getLabelForProposal(command.proposalSubmission);
|
||||||
|
@ -21,7 +21,7 @@ describe('TX: Transfer: getLabelForTransfer', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(getTypeLabelForTransfer(mock)).toEqual('Reward top up transfer');
|
expect(getTypeLabelForTransfer(mock)).toEqual('Reward transfer');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders reward top up label if the TO party is network', () => {
|
it('renders reward top up label if the TO party is network', () => {
|
||||||
@ -32,7 +32,7 @@ describe('TX: Transfer: getLabelForTransfer', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(getTypeLabelForTransfer(mock)).toEqual('Reward top up transfer');
|
expect(getTypeLabelForTransfer(mock)).toEqual('Reward transfer');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders recurring label if the tx has a recurring property', () => {
|
it('renders recurring label if the tx has a recurring property', () => {
|
||||||
@ -81,6 +81,7 @@ describe('TxDetailsTransfer', () => {
|
|||||||
hash: 'test',
|
hash: 'test',
|
||||||
submitter:
|
submitter:
|
||||||
'e1943eea46fed576cf2be42972f3c5515ad3d0ac7ac013f56677c12a53a1b3ed',
|
'e1943eea46fed576cf2be42972f3c5515ad3d0ac7ac013f56677c12a53a1b3ed',
|
||||||
|
block: '100',
|
||||||
command: {
|
command: {
|
||||||
nonce: '5188810881378065222',
|
nonce: '5188810881378065222',
|
||||||
blockHeight: '14951513',
|
blockHeight: '14951513',
|
||||||
|
@ -16,6 +16,8 @@ import { useBlockInfo } from '@vegaprotocol/tendermint';
|
|||||||
import { NodeLink } from '../../../components/links';
|
import { NodeLink } from '../../../components/links';
|
||||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||||
import EmptyList from '../../../components/empty-list/empty-list';
|
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 };
|
type Params = { block: string };
|
||||||
|
|
||||||
@ -26,6 +28,11 @@ const Block = () => {
|
|||||||
state: { data: blockData, loading, error },
|
state: { data: blockData, loading, error },
|
||||||
} = useBlockInfo(Number(block));
|
} = useBlockInfo(Number(block));
|
||||||
|
|
||||||
|
const { data } = useExplorerEpochForBlockQuery({
|
||||||
|
errorPolicy: 'ignore',
|
||||||
|
variables: { block: block?.toString() || '' },
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<RouteTitle data-testid="block-header">{t(`BLOCK ${block}`)}</RouteTitle>
|
<RouteTitle data-testid="block-header">{t(`BLOCK ${block}`)}</RouteTitle>
|
||||||
@ -75,6 +82,7 @@ const Block = () => {
|
|||||||
<code>{blockData.result.block.header.consensus_hash}</code>
|
<code>{blockData.result.block.header.consensus_hash}</code>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableHeader scope="row">Mined by</TableHeader>
|
<TableHeader scope="row">Mined by</TableHeader>
|
||||||
<TableCell modifier="bordered">
|
<TableCell modifier="bordered">
|
||||||
@ -97,6 +105,14 @@ const Block = () => {
|
|||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</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">
|
<TableRow modifier="bordered">
|
||||||
<TableHeader scope="row">Transactions</TableHeader>
|
<TableHeader scope="row">Transactions</TableHeader>
|
||||||
<TableCell modifier="bordered">
|
<TableCell modifier="bordered">
|
||||||
|
42
apps/explorer/src/app/routes/markets/market-oracles-page.tsx
Normal file
42
apps/explorer/src/app/routes/markets/market-oracles-page.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { useScrollToLocation } from '../../hooks/scroll-to-location';
|
||||||
|
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||||
|
import { PageTitle } from '../../components/page-helpers/page-title';
|
||||||
|
import { useExplorerOracleForMarketQuery } from '../oracles/__generated__/OraclesForMarkets';
|
||||||
|
import { OraclesTable } from '../../components/oracle-table';
|
||||||
|
|
||||||
|
type Params = { marketId: string };
|
||||||
|
|
||||||
|
export const MarketOraclesPage = () => {
|
||||||
|
useScrollToLocation();
|
||||||
|
|
||||||
|
const { marketId } = useParams<Params>();
|
||||||
|
const { data, error, loading } = useExplorerOracleForMarketQuery({
|
||||||
|
errorPolicy: 'ignore',
|
||||||
|
variables: {
|
||||||
|
id: marketId || '1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useDocumentTitle([marketId ? marketId : 'market', 'Oracles for Market']);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="relative">
|
||||||
|
<PageTitle
|
||||||
|
data-testid="markets-heading"
|
||||||
|
title={t('Oracles for market')}
|
||||||
|
/>
|
||||||
|
<AsyncRenderer
|
||||||
|
noDataMessage={t('This chain has no markets')}
|
||||||
|
errorMessage={t('Could not fetch market') + ' ' + marketId}
|
||||||
|
data={data}
|
||||||
|
loading={loading}
|
||||||
|
error={error}
|
||||||
|
>
|
||||||
|
<OraclesTable data={data} />
|
||||||
|
</AsyncRenderer>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
import { useScrollToLocation } from '../../hooks/scroll-to-location';
|
import { useScrollToLocation } from '../../hooks/scroll-to-location';
|
||||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||||
import { marketsProvider } from '@vegaprotocol/markets';
|
import { marketsWithDataProvider } from '@vegaprotocol/markets';
|
||||||
import { RouteTitle } from '../../components/route-title';
|
import { RouteTitle } from '../../components/route-title';
|
||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
@ -12,7 +12,7 @@ export const MarketsPage = () => {
|
|||||||
useScrollToLocation();
|
useScrollToLocation();
|
||||||
|
|
||||||
const { data, loading, error } = useDataProvider({
|
const { data, loading, error } = useDataProvider({
|
||||||
dataProvider: marketsProvider,
|
dataProvider: marketsWithDataProvider,
|
||||||
variables: undefined,
|
variables: undefined,
|
||||||
skipUpdates: true,
|
skipUpdates: true,
|
||||||
});
|
});
|
||||||
|
@ -89,7 +89,40 @@ fragment ExplorerOracleDataSourceSpec on ExternalDataSourceSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
query ExplorerOracleFormMarkets {
|
query ExplorerOracleFormMarkets {
|
||||||
marketsConnection {
|
marketsConnection(includeSettled: false, pagination: { first: 20 }) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
...ExplorerOracleForMarketsMarket
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oracleSpecsConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
dataSourceSpec {
|
||||||
|
...ExplorerOracleDataSourceSpec
|
||||||
|
}
|
||||||
|
dataConnection(pagination: { first: 1 }) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
externalData {
|
||||||
|
data {
|
||||||
|
data {
|
||||||
|
name
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query ExplorerOracleForMarket($id: ID!) {
|
||||||
|
marketsConnection(id: $id) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...ExplorerOracleForMarketsMarket
|
...ExplorerOracleForMarketsMarket
|
||||||
|
@ -16,6 +16,13 @@ export type ExplorerOracleFormMarketsQueryVariables = Types.Exact<{ [key: string
|
|||||||
|
|
||||||
export type ExplorerOracleFormMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Spot' } } } } }> } | null, oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } | { __typename?: 'EthCallSpec', address: string, sourceChainId: number } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
|
export type ExplorerOracleFormMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Spot' } } } } }> } | null, oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } | { __typename?: 'EthCallSpec', address: string, sourceChainId: number } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
|
||||||
|
|
||||||
|
export type ExplorerOracleForMarketQueryVariables = Types.Exact<{
|
||||||
|
id: Types.Scalars['ID'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ExplorerOracleForMarketQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Spot' } } } } }> } | null, oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } | { __typename?: 'EthCallSpec', address: string, sourceChainId: number } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
|
||||||
|
|
||||||
export const ExplorerOracleFutureFragmentDoc = gql`
|
export const ExplorerOracleFutureFragmentDoc = gql`
|
||||||
fragment ExplorerOracleFuture on Future {
|
fragment ExplorerOracleFuture on Future {
|
||||||
dataSourceSpecForSettlementData {
|
dataSourceSpecForSettlementData {
|
||||||
@ -113,7 +120,7 @@ export const ExplorerOracleDataSourceSpecFragmentDoc = gql`
|
|||||||
`;
|
`;
|
||||||
export const ExplorerOracleFormMarketsDocument = gql`
|
export const ExplorerOracleFormMarketsDocument = gql`
|
||||||
query ExplorerOracleFormMarkets {
|
query ExplorerOracleFormMarkets {
|
||||||
marketsConnection {
|
marketsConnection(includeSettled: false, pagination: {first: 20}) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...ExplorerOracleForMarketsMarket
|
...ExplorerOracleForMarketsMarket
|
||||||
@ -126,7 +133,7 @@ export const ExplorerOracleFormMarketsDocument = gql`
|
|||||||
dataSourceSpec {
|
dataSourceSpec {
|
||||||
...ExplorerOracleDataSourceSpec
|
...ExplorerOracleDataSourceSpec
|
||||||
}
|
}
|
||||||
dataConnection(pagination: {last: 1}) {
|
dataConnection(pagination: {first: 1}) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
externalData {
|
externalData {
|
||||||
@ -172,4 +179,67 @@ export function useExplorerOracleFormMarketsLazyQuery(baseOptions?: Apollo.LazyQ
|
|||||||
}
|
}
|
||||||
export type ExplorerOracleFormMarketsQueryHookResult = ReturnType<typeof useExplorerOracleFormMarketsQuery>;
|
export type ExplorerOracleFormMarketsQueryHookResult = ReturnType<typeof useExplorerOracleFormMarketsQuery>;
|
||||||
export type ExplorerOracleFormMarketsLazyQueryHookResult = ReturnType<typeof useExplorerOracleFormMarketsLazyQuery>;
|
export type ExplorerOracleFormMarketsLazyQueryHookResult = ReturnType<typeof useExplorerOracleFormMarketsLazyQuery>;
|
||||||
export type ExplorerOracleFormMarketsQueryResult = Apollo.QueryResult<ExplorerOracleFormMarketsQuery, ExplorerOracleFormMarketsQueryVariables>;
|
export type ExplorerOracleFormMarketsQueryResult = Apollo.QueryResult<ExplorerOracleFormMarketsQuery, ExplorerOracleFormMarketsQueryVariables>;
|
||||||
|
export const ExplorerOracleForMarketDocument = gql`
|
||||||
|
query ExplorerOracleForMarket($id: ID!) {
|
||||||
|
marketsConnection(id: $id) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
...ExplorerOracleForMarketsMarket
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oracleSpecsConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
dataSourceSpec {
|
||||||
|
...ExplorerOracleDataSourceSpec
|
||||||
|
}
|
||||||
|
dataConnection(pagination: {last: 1}) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
externalData {
|
||||||
|
data {
|
||||||
|
data {
|
||||||
|
name
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
${ExplorerOracleForMarketsMarketFragmentDoc}
|
||||||
|
${ExplorerOracleDataSourceSpecFragmentDoc}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useExplorerOracleForMarketQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useExplorerOracleForMarketQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useExplorerOracleForMarketQuery` 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 } = useExplorerOracleForMarketQuery({
|
||||||
|
* variables: {
|
||||||
|
* id: // value for 'id'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useExplorerOracleForMarketQuery(baseOptions: Apollo.QueryHookOptions<ExplorerOracleForMarketQuery, ExplorerOracleForMarketQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ExplorerOracleForMarketQuery, ExplorerOracleForMarketQueryVariables>(ExplorerOracleForMarketDocument, options);
|
||||||
|
}
|
||||||
|
export function useExplorerOracleForMarketLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerOracleForMarketQuery, ExplorerOracleForMarketQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ExplorerOracleForMarketQuery, ExplorerOracleForMarketQueryVariables>(ExplorerOracleForMarketDocument, options);
|
||||||
|
}
|
||||||
|
export type ExplorerOracleForMarketQueryHookResult = ReturnType<typeof useExplorerOracleForMarketQuery>;
|
||||||
|
export type ExplorerOracleForMarketLazyQueryHookResult = ReturnType<typeof useExplorerOracleForMarketLazyQuery>;
|
||||||
|
export type ExplorerOracleForMarketQueryResult = Apollo.QueryResult<ExplorerOracleForMarketQuery, ExplorerOracleForMarketQueryVariables>;
|
@ -4,8 +4,13 @@ import {
|
|||||||
ExternalExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../components/links/external-explorer-link/external-explorer-link';
|
} from '../../../components/links/external-explorer-link/external-explorer-link';
|
||||||
import { getExternalChainLabel } from '../../../components/links/external-explorer-link/external-chain';
|
import { getExternalChainLabel } from '@vegaprotocol/environment';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
|
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import isArray from 'lodash/isArray';
|
||||||
|
import type { components } from '../../../../types/explorer';
|
||||||
|
|
||||||
|
type Normalisers = components['schemas']['vegaNormaliser'][];
|
||||||
|
|
||||||
interface OracleDetailsEthSourceProps {
|
interface OracleDetailsEthSourceProps {
|
||||||
sourceType: SourceType;
|
sourceType: SourceType;
|
||||||
@ -34,21 +39,117 @@ export function OracleEthSource({
|
|||||||
|
|
||||||
const chainLabel = getExternalChainLabel(chain);
|
const chainLabel = getExternalChainLabel(chain);
|
||||||
|
|
||||||
|
const abi = prepareOracleSpecField(sourceType?.sourceType?.abi);
|
||||||
|
const args = prepareOracleSpecField(sourceType?.sourceType?.args);
|
||||||
|
const normalisers = serialiseNormalisers(sourceType.sourceType.normalisers);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableHeader scope="row">
|
<TableHeader scope="row" className="pt-1 align-text-top">
|
||||||
{chainLabel} {t('Contract')}
|
{chainLabel} {t('Contract')}
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableCell modifier="bordered">
|
<TableCell modifier="bordered">
|
||||||
<ExternalExplorerLink
|
<details>
|
||||||
chain={chain}
|
<summary className="cursor-pointer">
|
||||||
id={address}
|
<ExternalExplorerLink
|
||||||
type={EthExplorerLinkTypes.address}
|
chain={chain}
|
||||||
code={true}
|
id={address}
|
||||||
/>
|
type={EthExplorerLinkTypes.address}
|
||||||
<span className="mx-3">⇒</span>
|
code={true}
|
||||||
<code>{sourceType.sourceType.method}</code>
|
/>
|
||||||
|
<span className="mx-3">⇒</span>
|
||||||
|
<code>{sourceType.sourceType.method}</code>
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
{args && (
|
||||||
|
<>
|
||||||
|
<h2 className={'mt-5 mb-1 text-xl'}>{t('Arguments')}</h2>
|
||||||
|
<div className="max-w-3">
|
||||||
|
<SyntaxHighlighter
|
||||||
|
data={JSON.parse(
|
||||||
|
sourceType.sourceType.args as unknown as string
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{abi && (
|
||||||
|
<>
|
||||||
|
<h2 className={'mt-5 mb-1 text-xl'}>{t('ABI')}</h2>
|
||||||
|
<div className="max-w-3">
|
||||||
|
<SyntaxHighlighter data={abi} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{normalisers && (
|
||||||
|
<>
|
||||||
|
<h2 className={'mt-5 mb-1 text-xl'}>{t('Normalisers')}</h2>
|
||||||
|
<div className="max-w-3 mb-3">
|
||||||
|
<SyntaxHighlighter data={normalisers} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</details>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Constant to define the absence of a valid string from the Oracle Spec fields
|
||||||
|
const NO_DATA = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ABI and args are stored as either a (JSON escaped, probably) string
|
||||||
|
* or array of strings. Given that OracleEthSource is simply throwing the
|
||||||
|
* data in to a SyntaxHighlighter, we don't really care about the format,
|
||||||
|
* so this function will just try to parse the data and return it as a string.
|
||||||
|
*
|
||||||
|
* @param abi
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function prepareOracleSpecField(
|
||||||
|
specField?: string[] | null
|
||||||
|
): string | false {
|
||||||
|
if (!specField) {
|
||||||
|
return NO_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (isArray(specField)) {
|
||||||
|
return JSON.parse(specField.join(''));
|
||||||
|
} else {
|
||||||
|
return JSON.parse(specField);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return NO_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to prepareOracleSpecField above, but processes an array of normaliser objects
|
||||||
|
* removing the __typename and returning a serialised array of normalisers for
|
||||||
|
* SyntaxHighlighter
|
||||||
|
*
|
||||||
|
* @param normalisers
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function serialiseNormalisers(
|
||||||
|
normalisers?: Normalisers | null
|
||||||
|
): Normalisers | false {
|
||||||
|
if (!normalisers) {
|
||||||
|
return NO_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return normalisers.map((normaliser) => {
|
||||||
|
return {
|
||||||
|
name: normaliser.name,
|
||||||
|
expression: normaliser.expression,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
return NO_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,38 +1,9 @@
|
|||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import { OracleFilter } from './oracle-filter';
|
import { OracleFilter } from './oracle-filter';
|
||||||
import type { ExplorerOracleDataSourceFragment } from '../__generated__/Oracles';
|
import type { ExplorerOracleDataSourceFragment } from '../__generated__/Oracles';
|
||||||
import {
|
import { ConditionOperator, DataSourceSpecStatus } from '@vegaprotocol/types';
|
||||||
ConditionOperator,
|
|
||||||
DataSourceSpecStatus,
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '@vegaprotocol/types';
|
|
||||||
import type { Condition } from '@vegaprotocol/types';
|
import type { Condition } from '@vegaprotocol/types';
|
||||||
|
|
||||||
type Spec =
|
|
||||||
ExplorerOracleDataSourceFragment['dataSourceSpec']['spec']['data']['sourceType'];
|
|
||||||
|
|
||||||
const mockExternalSpec: Spec = {
|
|
||||||
sourceType: {
|
|
||||||
__typename: 'DataSourceSpecConfiguration',
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
__typename: 'Filter',
|
|
||||||
key: {
|
|
||||||
type: PropertyKeyType.TYPE_INTEGER,
|
|
||||||
name: 'testKey',
|
|
||||||
},
|
|
||||||
conditions: [
|
|
||||||
{
|
|
||||||
__typename: 'Condition',
|
|
||||||
value: 'testValue',
|
|
||||||
operator: ConditionOperator.OPERATOR_EQUALS,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function renderComponent(data: ExplorerOracleDataSourceFragment) {
|
function renderComponent(data: ExplorerOracleDataSourceFragment) {
|
||||||
return <OracleFilter data={data} />;
|
return <OracleFilter data={data} />;
|
||||||
}
|
}
|
||||||
@ -50,31 +21,6 @@ describe('Oracle Filter view', () => {
|
|||||||
expect(res.container).toBeEmptyDOMElement();
|
expect(res.container).toBeEmptyDOMElement();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Renders filters if type is DataSourceSpecConfiguration', () => {
|
|
||||||
const res = render(
|
|
||||||
renderComponent({
|
|
||||||
dataSourceSpec: {
|
|
||||||
spec: {
|
|
||||||
id: 'irrelevant-test-data',
|
|
||||||
createdAt: 'irrelevant-test-data',
|
|
||||||
status: DataSourceSpecStatus.STATUS_ACTIVE,
|
|
||||||
data: {
|
|
||||||
sourceType: mockExternalSpec,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dataConnection: {
|
|
||||||
edges: [],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// Renders a comprehensible summary of key = value
|
|
||||||
expect(res.getByText('testKey')).toBeInTheDocument();
|
|
||||||
expect(res.getByText('=')).toBeInTheDocument();
|
|
||||||
expect(res.getByText('testValue')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Renders conditions if type is DataSourceSpecConfigurationTime', () => {
|
it('Renders conditions if type is DataSourceSpecConfigurationTime', () => {
|
||||||
const res = render(
|
const res = render(
|
||||||
renderComponent({
|
renderComponent({
|
||||||
@ -136,7 +82,7 @@ describe('Oracle Filter view', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// This should never happen, but for coverage sake we test that it does this
|
// This should never happen, but for coverage we test that it does this
|
||||||
const ul = res.getByRole('list');
|
const ul = res.getByRole('list');
|
||||||
expect(ul).toBeInTheDocument();
|
expect(ul).toBeInTheDocument();
|
||||||
expect(ul).toBeEmptyDOMElement();
|
expect(ul).toBeEmptyDOMElement();
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import type { ExplorerOracleDataSourceFragment } from '../__generated__/Oracles';
|
import type { ExplorerOracleDataSourceFragment } from '../__generated__/Oracles';
|
||||||
import { OracleSpecInternalTimeTrigger } from './oracle-spec/internal-time-trigger';
|
import {
|
||||||
|
OracleSpecInternalTimeTrigger,
|
||||||
|
TimeTrigger,
|
||||||
|
} from './oracle-spec/internal-time-trigger';
|
||||||
import { OracleSpecCondition } from './oracle-spec/condition';
|
import { OracleSpecCondition } from './oracle-spec/condition';
|
||||||
import { getCharacterForOperator } from './oracle-spec/operator';
|
import { getCharacterForOperator } from './oracle-spec/operator';
|
||||||
|
|
||||||
@ -11,7 +14,7 @@ interface OracleFilterProps {
|
|||||||
* Shows the conditions that this oracle is using to filter
|
* Shows the conditions that this oracle is using to filter
|
||||||
* data sources, as a list.
|
* data sources, as a list.
|
||||||
*
|
*
|
||||||
* Renders nothing if there is no data (which will frequently)
|
* Renders nothing if there is no data (which will frequently
|
||||||
* be the case) and if there is data, currently renders a simple
|
* be the case) and if there is data, currently renders a simple
|
||||||
* JSON view.
|
* JSON view.
|
||||||
*/
|
*/
|
||||||
@ -21,6 +24,7 @@ export function OracleFilter({ data }: OracleFilterProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const s = data.dataSourceSpec.spec.data.sourceType.sourceType;
|
const s = data.dataSourceSpec.spec.data.sourceType.sourceType;
|
||||||
|
|
||||||
if (s.__typename === 'DataSourceSpecConfigurationTime' && s.conditions) {
|
if (s.__typename === 'DataSourceSpecConfigurationTime' && s.conditions) {
|
||||||
return (
|
return (
|
||||||
<ul>
|
<ul>
|
||||||
@ -41,30 +45,30 @@ export function OracleFilter({ data }: OracleFilterProps) {
|
|||||||
s.triggers
|
s.triggers
|
||||||
) {
|
) {
|
||||||
return <OracleSpecInternalTimeTrigger data={s} />;
|
return <OracleSpecInternalTimeTrigger data={s} />;
|
||||||
} else if (
|
} else if (s.__typename === 'EthCallSpec') {
|
||||||
s.__typename === 'EthCallSpec' ||
|
|
||||||
s.__typename === 'DataSourceSpecConfiguration'
|
|
||||||
) {
|
|
||||||
if (s.filters !== null && s.filters && 'filters' in s) {
|
if (s.filters !== null && s.filters && 'filters' in s) {
|
||||||
return (
|
return (
|
||||||
<ul>
|
<div>
|
||||||
{s.filters.map((f) => {
|
<ul>
|
||||||
const prop = <code title={f.key.type}>{f.key.name}</code>;
|
{s.filters.map((f) => {
|
||||||
|
const prop = <code title={f.key.type}>{f.key.name}</code>;
|
||||||
|
|
||||||
if (!f.conditions || f.conditions.length === 0) {
|
if (!f.conditions || f.conditions.length === 0) {
|
||||||
return prop;
|
return prop;
|
||||||
} else {
|
} else {
|
||||||
return f.conditions.map((c) => {
|
return f.conditions.map((c) => {
|
||||||
return (
|
return (
|
||||||
<li key={`${prop}${c.value}`}>
|
<li key={`${prop}${c.value}`}>
|
||||||
{prop} {getCharacterForOperator(c.operator)}{' '}
|
{prop} {getCharacterForOperator(c.operator)}{' '}
|
||||||
<code>{c.value ? c.value : '-'}</code>
|
<code>{c.value ? c.value : '-'}</code>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
|
{s.trigger && <TimeTrigger data={s.trigger.trigger} />}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { DataSourceSpecConfigurationTimeTrigger } from '@vegaprotocol/types';
|
import type {
|
||||||
|
DataSourceSpecConfigurationTimeTrigger,
|
||||||
|
EthTimeTrigger,
|
||||||
|
InternalTimeTrigger,
|
||||||
|
Maybe,
|
||||||
|
} from '@vegaprotocol/types';
|
||||||
import secondsToMinutes from 'date-fns/secondsToMinutes';
|
import secondsToMinutes from 'date-fns/secondsToMinutes';
|
||||||
import fromUnixTime from 'date-fns/fromUnixTime';
|
import fromUnixTime from 'date-fns/fromUnixTime';
|
||||||
|
|
||||||
@ -13,32 +18,60 @@ export function OracleSpecInternalTimeTrigger({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<span>{t('Time')}</span>,
|
<span>{t('Time')}</span>,
|
||||||
{data.triggers.map((tr) => {
|
{data.triggers.map((tr) => (
|
||||||
return (
|
<TimeTrigger data={tr} />
|
||||||
<span>
|
))}
|
||||||
{tr?.initial ? (
|
|
||||||
<span title={`${tr.initial}`}>
|
|
||||||
<strong>{t('starting at')}</strong>{' '}
|
|
||||||
<em className="not-italic underline decoration-dotted">
|
|
||||||
{fromUnixTime(tr.initial).toLocaleString()}
|
|
||||||
</em>
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
{tr?.every ? (
|
|
||||||
<span title={`${tr.every} ${t('seconds')}`}>
|
|
||||||
, <strong>{t('every')}</strong>{' '}
|
|
||||||
<em className="not-italic underline decoration-dotted">
|
|
||||||
{secondsToMinutes(tr.every)} {t('minutes')}
|
|
||||||
</em>{' '}
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TimeTriggerProps {
|
||||||
|
data: Maybe<InternalTimeTrigger> | Maybe<EthTimeTrigger>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TimeTrigger({ data }: TimeTriggerProps) {
|
||||||
|
const d = parseDate(data?.initial);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span key={JSON.stringify(data)}>
|
||||||
|
{data?.initial ? (
|
||||||
|
<span title={`${data.initial}`}>
|
||||||
|
<strong>{t('starting at')}</strong>{' '}
|
||||||
|
<em className="not-italic underline decoration-dotted">{d}</em>
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
{data?.every ? (
|
||||||
|
<span title={`${data.every} ${t('seconds')}`}>
|
||||||
|
, <strong>{t('every')}</strong>{' '}
|
||||||
|
<em className="not-italic underline decor</em>ation-dotted">
|
||||||
|
{secondsToMinutes(data.every)} {t('minutes')}
|
||||||
|
</em>{' '}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dates in oracle triggers can be (or maybe were previously) Unix Time or timestamps
|
||||||
|
* depending on type. This function handles both cases and returns a nicely formatted date.
|
||||||
|
*
|
||||||
|
* @param date
|
||||||
|
* @returns string Localestring for date
|
||||||
|
*/
|
||||||
|
export function parseDate(date?: string | number): string {
|
||||||
|
if (!date) {
|
||||||
|
return 'Invalid date';
|
||||||
|
}
|
||||||
|
const d = fromUnixTime(+date).toLocaleString();
|
||||||
|
|
||||||
|
if (d === 'Invalid Date') {
|
||||||
|
return new Date(date).toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
@ -48,6 +48,11 @@ export const OracleDetails = ({
|
|||||||
? dataSource.dataSourceSpec.spec.data.sourceType.sourceType.sourceChainId.toString()
|
? dataSource.dataSourceSpec.spec.data.sourceType.sourceType.sourceChainId.toString()
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const requiredConfirmations =
|
||||||
|
(sourceType.sourceType.__typename === 'EthCallSpec' &&
|
||||||
|
sourceType.sourceType.requiredConfirmations) ||
|
||||||
|
'';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<TableWithTbody className="mb-2">
|
<TableWithTbody className="mb-2">
|
||||||
@ -64,15 +69,23 @@ export const OracleDetails = ({
|
|||||||
{getStatusString(dataSource.dataSourceSpec.spec.status)}
|
{getStatusString(dataSource.dataSourceSpec.spec.status)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
<OracleMarkets id={id} />
|
||||||
<OracleSigners sourceType={sourceType} />
|
<OracleSigners sourceType={sourceType} />
|
||||||
<OracleEthSource sourceType={sourceType} chain={chain} />
|
<OracleEthSource sourceType={sourceType} chain={chain} />
|
||||||
<OracleMarkets id={id} />
|
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableHeader scope="row">{t('Filter')}</TableHeader>
|
<TableHeader scope="row" className="pt-1 align-text-top">
|
||||||
|
{t('Filter')}
|
||||||
|
</TableHeader>
|
||||||
<TableCell modifier="bordered">
|
<TableCell modifier="bordered">
|
||||||
<OracleFilter data={dataSource} />
|
<OracleFilter data={dataSource} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
{requiredConfirmations && requiredConfirmations > 0 && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableHeader scope="row">{t('Required Confirmations')}</TableHeader>
|
||||||
|
<TableCell modifier="bordered">{requiredConfirmations}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
</TableWithTbody>
|
</TableWithTbody>
|
||||||
{dataConnection ? <OracleData data={dataConnection} /> : null}
|
{dataConnection ? <OracleData data={dataConnection} /> : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
import compact from 'lodash/compact';
|
|
||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import { RouteTitle } from '../../../components/route-title';
|
import { RouteTitle } from '../../../components/route-title';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||||
import { useScrollToLocation } from '../../../hooks/scroll-to-location';
|
import { useScrollToLocation } from '../../../hooks/scroll-to-location';
|
||||||
import { useExplorerOracleFormMarketsQuery } from '../__generated__/OraclesForMarkets';
|
import { useExplorerOracleFormMarketsQuery } from '../__generated__/OraclesForMarkets';
|
||||||
import { MarketLink } from '../../../components/links';
|
import { OraclesTable } from '../../../components/oracle-table';
|
||||||
import { OracleLink } from '../../../components/links/oracle-link/oracle-link';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { MarketStateMapping } from '@vegaprotocol/types';
|
|
||||||
import type { MarketState } from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
const cellSpacing = 'px-3';
|
|
||||||
|
|
||||||
const Oracles = () => {
|
const Oracles = () => {
|
||||||
const { data, loading, error } = useExplorerOracleFormMarketsQuery({
|
const { data, loading, error } = useExplorerOracleFormMarketsQuery({
|
||||||
@ -21,8 +14,6 @@ const Oracles = () => {
|
|||||||
useDocumentTitle(['Oracles']);
|
useDocumentTitle(['Oracles']);
|
||||||
useScrollToLocation();
|
useScrollToLocation();
|
||||||
|
|
||||||
const [hoveredOracle, setHoveredOracle] = useState('');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<RouteTitle data-testid="oracle-specs-heading">{t('Oracles')}</RouteTitle>
|
<RouteTitle data-testid="oracle-specs-heading">{t('Oracles')}</RouteTitle>
|
||||||
@ -38,148 +29,7 @@ const Oracles = () => {
|
|||||||
data.oracleSpecsConnection.edges?.length === 0
|
data.oracleSpecsConnection.edges?.length === 0
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<table className="text-left">
|
<OraclesTable data={data} />
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th className={cellSpacing}>Market</th>
|
|
||||||
<th className={cellSpacing}>Type</th>
|
|
||||||
<th className={cellSpacing}>State</th>
|
|
||||||
<th className={cellSpacing}>Settlement</th>
|
|
||||||
<th className={cellSpacing}>Termination</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{data?.marketsConnection?.edges
|
|
||||||
? data.marketsConnection.edges.map((o) => {
|
|
||||||
let hasSeenOracleReports = false;
|
|
||||||
let settlementOracle = '-';
|
|
||||||
let settlementOracleStatus = '-';
|
|
||||||
let terminationOracle = '-';
|
|
||||||
let terminationOracleStatus = '-';
|
|
||||||
|
|
||||||
const id = o?.node.id;
|
|
||||||
if (!id) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
o.node.tradableInstrument.instrument.product.__typename ===
|
|
||||||
'Future'
|
|
||||||
) {
|
|
||||||
settlementOracle =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementData.id;
|
|
||||||
terminationOracle =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForTradingTermination.id;
|
|
||||||
settlementOracleStatus =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementData.status;
|
|
||||||
terminationOracleStatus =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForTradingTermination.status;
|
|
||||||
} else if (
|
|
||||||
o.node.tradableInstrument.instrument.product.__typename ===
|
|
||||||
'Perpetual'
|
|
||||||
) {
|
|
||||||
settlementOracle =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementData.id;
|
|
||||||
terminationOracle =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementSchedule.id;
|
|
||||||
settlementOracleStatus =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementData.status;
|
|
||||||
terminationOracleStatus =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementSchedule.status;
|
|
||||||
}
|
|
||||||
const oracleInformationUnfiltered =
|
|
||||||
data?.oracleSpecsConnection?.edges?.map((e) =>
|
|
||||||
e && e.node ? e.node : undefined
|
|
||||||
) || [];
|
|
||||||
|
|
||||||
const oracleInformation = compact(oracleInformationUnfiltered)
|
|
||||||
.filter(
|
|
||||||
(o) =>
|
|
||||||
o.dataConnection.edges &&
|
|
||||||
o.dataConnection.edges.length > 0 &&
|
|
||||||
(o.dataSourceSpec.spec.id === settlementOracle ||
|
|
||||||
o.dataSourceSpec.spec.id === terminationOracle)
|
|
||||||
)
|
|
||||||
.at(0);
|
|
||||||
if (oracleInformation) {
|
|
||||||
hasSeenOracleReports = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const oracleList = `${settlementOracle} ${terminationOracle}`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<tr
|
|
||||||
id={id}
|
|
||||||
key={id}
|
|
||||||
className={
|
|
||||||
hoveredOracle.length > 0 &&
|
|
||||||
oracleList.indexOf(hoveredOracle) > -1
|
|
||||||
? 'bg-gray-100 dark:bg-gray-800'
|
|
||||||
: ''
|
|
||||||
}
|
|
||||||
data-testid="oracle-details"
|
|
||||||
data-oracles={oracleList}
|
|
||||||
>
|
|
||||||
<td className={cellSpacing}>
|
|
||||||
<MarketLink id={id} />
|
|
||||||
</td>
|
|
||||||
<td className={cellSpacing}>
|
|
||||||
{
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.__typename
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
<td className={cellSpacing}>
|
|
||||||
{MarketStateMapping[o.node.state as MarketState]}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className={
|
|
||||||
hoveredOracle.length > 0 &&
|
|
||||||
hoveredOracle === settlementOracle
|
|
||||||
? `indent-1 ${cellSpacing}`
|
|
||||||
: cellSpacing
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<OracleLink
|
|
||||||
id={settlementOracle}
|
|
||||||
status={settlementOracleStatus}
|
|
||||||
hasSeenOracleReports={hasSeenOracleReports}
|
|
||||||
onMouseOver={() => setHoveredOracle(settlementOracle)}
|
|
||||||
onMouseOut={() => setHoveredOracle('')}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className={
|
|
||||||
hoveredOracle.length > 0 &&
|
|
||||||
hoveredOracle === terminationOracle
|
|
||||||
? `indent-1 ${cellSpacing}`
|
|
||||||
: cellSpacing
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<OracleLink
|
|
||||||
id={terminationOracle}
|
|
||||||
status={terminationOracleStatus}
|
|
||||||
hasSeenOracleReports={hasSeenOracleReports}
|
|
||||||
onMouseOver={() =>
|
|
||||||
setHoveredOracle(terminationOracle)
|
|
||||||
}
|
|
||||||
onMouseOut={() => setHoveredOracle('')}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: null}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</AsyncRenderer>
|
</AsyncRenderer>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,7 @@ import { useMemo, useState } from 'react';
|
|||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { SubHeading } from '../../../components/sub-heading';
|
import { SubHeading } from '../../../components/sub-heading';
|
||||||
import { toNonHex } from '../../../components/search/detect-search';
|
import { toNonHex } from '../../../components/search/detect-search';
|
||||||
import { useTxsData } from '../../../hooks/use-txs-data';
|
import { getInitialFilters, useTxsData } from '../../../hooks/use-txs-data';
|
||||||
import { TxsInfiniteList } from '../../../components/txs';
|
import { TxsInfiniteList } from '../../../components/txs';
|
||||||
import { PageHeader } from '../../../components/page-header';
|
import { PageHeader } from '../../../components/page-header';
|
||||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||||
@ -15,16 +15,18 @@ import { PartyBlockAccounts } from './components/party-block-accounts';
|
|||||||
import { isValidPartyId } from './components/party-id-error';
|
import { isValidPartyId } from './components/party-id-error';
|
||||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
|
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
|
||||||
import type { FilterOption } from '../../../components/txs/tx-filter';
|
import {
|
||||||
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
|
TxsFilter,
|
||||||
|
type FilterOption,
|
||||||
|
} from '../../../components/txs/tx-filter';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
type Params = { party: string };
|
type Params = { party: string };
|
||||||
|
|
||||||
const Party = () => {
|
const Party = () => {
|
||||||
const [params] = useSearchParams();
|
const [params] = useSearchParams();
|
||||||
|
const [filters, setFilters] = useState(getInitialFilters(params));
|
||||||
|
|
||||||
const [filters, setFilters] = useState(new Set(AllFilterOptions));
|
|
||||||
const { party } = useParams<Params>();
|
const { party } = useParams<Params>();
|
||||||
|
|
||||||
useDocumentTitle(['Public keys', party || '-']);
|
useDocumentTitle(['Public keys', party || '-']);
|
||||||
|
@ -5,9 +5,8 @@ import Home from './home';
|
|||||||
import OraclePage from './oracles';
|
import OraclePage from './oracles';
|
||||||
import Oracles from './oracles/home';
|
import Oracles from './oracles/home';
|
||||||
import { Oracle } from './oracles/id';
|
import { Oracle } from './oracles/id';
|
||||||
import Party from './parties';
|
|
||||||
import { Parties } from './parties/home';
|
import { Parties } from './parties/home';
|
||||||
import { Party as PartySingle } from './parties/id';
|
import { Party } from './parties/id';
|
||||||
import { ValidatorsPage } from './validators';
|
import { ValidatorsPage } from './validators';
|
||||||
import Genesis from './genesis';
|
import Genesis from './genesis';
|
||||||
import { Block } from './blocks/id';
|
import { Block } from './blocks/id';
|
||||||
@ -17,6 +16,7 @@ import { TxsList } from './txs/home';
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Routes } from './route-names';
|
import { Routes } from './route-names';
|
||||||
import { NetworkParameters } from './network-parameters';
|
import { NetworkParameters } from './network-parameters';
|
||||||
|
import { Outlet } from 'react-router-dom';
|
||||||
import type { Params, RouteObject } from 'react-router-dom';
|
import type { Params, RouteObject } from 'react-router-dom';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { MarketPage, MarketsPage } from './markets';
|
import { MarketPage, MarketsPage } from './markets';
|
||||||
@ -31,6 +31,7 @@ import { Disclaimer } from './pages/disclaimer';
|
|||||||
import { useFeatureFlags } from '@vegaprotocol/environment';
|
import { useFeatureFlags } from '@vegaprotocol/environment';
|
||||||
import RestrictedPage from './restricted';
|
import RestrictedPage from './restricted';
|
||||||
import { NetworkTreasury } from './treasury';
|
import { NetworkTreasury } from './treasury';
|
||||||
|
import { MarketOraclesPage } from './markets/market-oracles-page';
|
||||||
|
|
||||||
export type Navigable = {
|
export type Navigable = {
|
||||||
path: string;
|
path: string;
|
||||||
@ -67,7 +68,7 @@ export const useRouterConfig = () => {
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
path: Routes.PARTIES,
|
path: Routes.PARTIES,
|
||||||
element: <Party />,
|
element: <Outlet />,
|
||||||
handle: {
|
handle: {
|
||||||
name: t('Parties'),
|
name: t('Parties'),
|
||||||
text: t('Parties'),
|
text: t('Parties'),
|
||||||
@ -80,12 +81,12 @@ export const useRouterConfig = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':party',
|
path: ':party',
|
||||||
element: <Party />,
|
element: <Outlet />,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
index: true,
|
index: true,
|
||||||
element: <PartySingle />,
|
element: <Party />,
|
||||||
handle: {
|
handle: {
|
||||||
breadcrumb: (params: Params<string>) => (
|
breadcrumb: (params: Params<string>) => (
|
||||||
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
||||||
@ -96,7 +97,7 @@ export const useRouterConfig = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'assets',
|
path: 'assets',
|
||||||
element: <Party />,
|
element: <Outlet />,
|
||||||
handle: {
|
handle: {
|
||||||
breadcrumb: (params: Params<string>) => (
|
breadcrumb: (params: Params<string>) => (
|
||||||
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
||||||
@ -199,12 +200,36 @@ export const useRouterConfig = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':marketId',
|
path: ':marketId',
|
||||||
element: <MarketPage />,
|
element: <Outlet />,
|
||||||
handle: {
|
children: [
|
||||||
breadcrumb: (params: Params<string>) => (
|
{
|
||||||
<MarketLink id={params.marketId as string} />
|
index: true,
|
||||||
),
|
element: <MarketPage />,
|
||||||
},
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<MarketLink id={params.marketId as string} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'oracles',
|
||||||
|
element: <Outlet />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<MarketLink id={params.marketId as string} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <MarketOraclesPage />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => t('Oracles'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -33,7 +33,10 @@ export const NetworkAccountsTable = () => {
|
|||||||
return (
|
return (
|
||||||
<section className="md:flex md:flex-row flex-wrap">
|
<section className="md:flex md:flex-row flex-wrap">
|
||||||
{c.map((a) => (
|
{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="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">
|
<div className="text-center p-6 bg-gray-100 dark:bg-slate-900 border-b dark:border-slate-500">
|
||||||
<p className="flex justify-center">
|
<p className="flex justify-center">
|
||||||
|
@ -16,19 +16,21 @@ import type { DeepPartial } from '@apollo/client/utilities';
|
|||||||
|
|
||||||
describe('typeLabel', () => {
|
describe('typeLabel', () => {
|
||||||
it('should return "Transfer" for "OneOffTransfer" kind', () => {
|
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', () => {
|
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', () => {
|
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', () => {
|
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', () => {
|
it('should return "Unknown" for unknown kind', () => {
|
||||||
@ -256,7 +258,7 @@ describe('NetworkTransfersTable', () => {
|
|||||||
expect(screen.getByTestId('from-account').textContent).toEqual('Treasury');
|
expect(screen.getByTestId('from-account').textContent).toEqual('Treasury');
|
||||||
expect(screen.getByTestId('to-account').textContent).toEqual('7100…97a0');
|
expect(screen.getByTestId('to-account').textContent).toEqual('7100…97a0');
|
||||||
expect(screen.getByTestId('transfer-kind').textContent).toEqual(
|
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 { IconNames } from '@blueprintjs/icons';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||||
|
import ProposalLink from '../../../components/links/proposal-link/proposal-link';
|
||||||
|
|
||||||
export const colours = {
|
export const colours = {
|
||||||
INCOMING: '!fill-vega-green-600 text-vega-green-600 mr-2',
|
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 {
|
export function typeLabel(kind?: string): string {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case 'OneOffTransfer':
|
case 'OneOffTransfer':
|
||||||
|
return t('Transfer - one time');
|
||||||
case 'RecurringTransfer':
|
case 'RecurringTransfer':
|
||||||
return t('Transfer');
|
return t('Transfer - repeating');
|
||||||
case 'OneOffGovernanceTransfer':
|
case 'OneOffGovernanceTransfer':
|
||||||
|
return t('Governance - one time');
|
||||||
case 'RecurringGovernanceTransfer':
|
case 'RecurringGovernanceTransfer':
|
||||||
return t('Governance');
|
return t('Governance - repeating');
|
||||||
default:
|
default:
|
||||||
return t('Unknown');
|
return t('Unknown');
|
||||||
}
|
}
|
||||||
@ -239,6 +250,11 @@ export const NetworkTransfersTable = () => {
|
|||||||
>
|
>
|
||||||
{a && typeLabel(a.kind.__typename)}
|
{a && typeLabel(a.kind.__typename)}
|
||||||
</span>
|
</span>
|
||||||
|
{isGovernanceTransfer(a?.kind.__typename) && a?.id && (
|
||||||
|
<span className="ml-4">
|
||||||
|
<ProposalLink id={a?.id} text="View" />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
@ -4,6 +4,7 @@ import { t } from '@vegaprotocol/i18n';
|
|||||||
import { RouteTitle } from '../../components/route-title';
|
import { RouteTitle } from '../../components/route-title';
|
||||||
import { NetworkAccountsTable } from './components/network-accounts-table';
|
import { NetworkAccountsTable } from './components/network-accounts-table';
|
||||||
import { NetworkTransfersTable } from './components/network-transfers-table';
|
import { NetworkTransfersTable } from './components/network-transfers-table';
|
||||||
|
import GovernanceLink from '../../components/links/governance-link/governance-link';
|
||||||
|
|
||||||
export type NonZeroAccount = {
|
export type NonZeroAccount = {
|
||||||
assetId: string;
|
assetId: string;
|
||||||
@ -16,7 +17,33 @@ export const NetworkTreasury = () => {
|
|||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<RouteTitle data-testid="block-header">{t(`Treasury`)}</RouteTitle>
|
<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 />
|
<NetworkAccountsTable />
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_VEGA_ENV=VALIDATOR_TESTNET
|
NX_VEGA_ENV=VALIDATORS_TESTNET
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
|
||||||
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
||||||
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
||||||
|
@ -47,7 +47,7 @@ export const SubHeading = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<h2
|
<h2
|
||||||
className={classNames('text-2xl font-alpha calt uppercase break-words', {
|
className={classNames('text-2xl font-alpha calt break-words', {
|
||||||
'mx-auto': centerContent,
|
'mx-auto': centerContent,
|
||||||
'mb-0': !marginBottom,
|
'mb-0': !marginBottom,
|
||||||
'mb-4': marginBottom,
|
'mb-4': marginBottom,
|
||||||
|
@ -41,7 +41,7 @@ export const ContractAddresses: {
|
|||||||
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
|
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
|
||||||
lockedAddress: '0x0', // TODO not deployed to this env
|
lockedAddress: '0x0', // TODO not deployed to this env
|
||||||
},
|
},
|
||||||
VALIDATOR_TESTNET: {
|
VALIDATORS_TESTNET: {
|
||||||
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
|
claimAddress: '0x8Cef746ab7C83B61F6461cC92882bD61AB65a994', // TODO not deployed to this env, but random address so app doesn't error
|
||||||
lockedAddress: '0x0', // TODO not deployed to this env
|
lockedAddress: '0x0', // TODO not deployed to this env
|
||||||
// This is a fallback contract address for the validator testnet network which does not
|
// This is a fallback contract address for the validator testnet network which does not
|
||||||
|
@ -6,10 +6,11 @@ import {
|
|||||||
ViewPartyConnector,
|
ViewPartyConnector,
|
||||||
createConfig,
|
createConfig,
|
||||||
fairground,
|
fairground,
|
||||||
|
validatorsTestnet,
|
||||||
stagnet,
|
stagnet,
|
||||||
mainnet,
|
mainnet,
|
||||||
} from '@vegaprotocol/wallet';
|
} from '@vegaprotocol/wallet';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { CHAIN_IDS, useEnvironment } from '@vegaprotocol/environment';
|
||||||
|
|
||||||
export const useVegaWalletConfig = () => {
|
export const useVegaWalletConfig = () => {
|
||||||
const { VEGA_ENV, VEGA_URL, VEGA_WALLET_URL } = useEnvironment();
|
const { VEGA_ENV, VEGA_URL, VEGA_WALLET_URL } = useEnvironment();
|
||||||
@ -31,8 +32,8 @@ export const useVegaWalletConfig = () => {
|
|||||||
const viewParty = new ViewPartyConnector();
|
const viewParty = new ViewPartyConnector();
|
||||||
|
|
||||||
const config = createConfig({
|
const config = createConfig({
|
||||||
chains: [mainnet, fairground, stagnet],
|
chains: [mainnet, fairground, validatorsTestnet, stagnet],
|
||||||
defaultChainId: fairground.id,
|
defaultChainId: CHAIN_IDS[VEGA_ENV],
|
||||||
connectors: [injected, snap, jsonRpc, viewParty],
|
connectors: [injected, snap, jsonRpc, viewParty],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ i18n
|
|||||||
load: 'languageOnly',
|
load: 'languageOnly',
|
||||||
debug: isInDev,
|
debug: isInDev,
|
||||||
// have a common namespace used around the full app
|
// have a common namespace used around the full app
|
||||||
ns: ['governance', 'wallet', 'wallet-react'],
|
ns: ['governance', 'wallet', 'wallet-react', 'assets', 'utils'],
|
||||||
defaultNS: 'governance',
|
defaultNS: 'governance',
|
||||||
keySeparator: false, // we use content as keys
|
keySeparator: false, // we use content as keys
|
||||||
nsSeparator: false,
|
nsSeparator: false,
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
getSigners,
|
getSigners,
|
||||||
MarginScalingFactorsPanel,
|
MarginScalingFactorsPanel,
|
||||||
marketInfoProvider,
|
marketInfoProvider,
|
||||||
|
PriceMonitoringSettingsInfoPanel,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@ -49,7 +50,7 @@ export const useMarketDataDialogStore = create<MarketDataDialogState>(
|
|||||||
const marketDataHeaderStyles =
|
const marketDataHeaderStyles =
|
||||||
'font-alpha calt text-base border-b border-vega-dark-200 mt-2 py-2';
|
'font-alpha calt text-base border-b border-vega-dark-200 mt-2 py-2';
|
||||||
|
|
||||||
export const ProposalMarketData = ({ proposalId }: { proposalId: string }) => {
|
export const ProposalMarketData = ({ marketId }: { marketId: string }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isOpen, open, close } = useMarketDataDialogStore();
|
const { isOpen, open, close } = useMarketDataDialogStore();
|
||||||
const [showDetails, setShowDetails] = useState(false);
|
const [showDetails, setShowDetails] = useState(false);
|
||||||
@ -58,7 +59,7 @@ export const ProposalMarketData = ({ proposalId }: { proposalId: string }) => {
|
|||||||
dataProvider: marketInfoProvider,
|
dataProvider: marketInfoProvider,
|
||||||
skipUpdates: true,
|
skipUpdates: true,
|
||||||
variables: {
|
variables: {
|
||||||
marketId: proposalId,
|
marketId: marketId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -71,7 +72,7 @@ export const ProposalMarketData = ({ proposalId }: { proposalId: string }) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!marketData || !parentMarketData) {
|
if (!marketData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,13 +134,13 @@ export const ProposalMarketData = ({ proposalId }: { proposalId: string }) => {
|
|||||||
<h2 className={marketDataHeaderStyles}>{t('Key details')}</h2>
|
<h2 className={marketDataHeaderStyles}>{t('Key details')}</h2>
|
||||||
<KeyDetailsInfoPanel
|
<KeyDetailsInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
parentMarket={parentMarketData}
|
parentMarket={parentMarketData ? parentMarketData : undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2 className={marketDataHeaderStyles}>{t('Instrument')}</h2>
|
<h2 className={marketDataHeaderStyles}>{t('Instrument')}</h2>
|
||||||
<InstrumentInfoPanel
|
<InstrumentInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
parentMarket={parentMarketData}
|
parentMarket={parentMarketData ? parentMarketData : undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{settlementData &&
|
{settlementData &&
|
||||||
@ -155,7 +156,7 @@ export const ProposalMarketData = ({ proposalId }: { proposalId: string }) => {
|
|||||||
isParentSettlementDataEqual ||
|
isParentSettlementDataEqual ||
|
||||||
isParentSettlementScheduleDataEqual
|
isParentSettlementScheduleDataEqual
|
||||||
? undefined
|
? undefined
|
||||||
: parentMarketData
|
: parentMarketData || undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
@ -168,7 +169,9 @@ export const ProposalMarketData = ({ proposalId }: { proposalId: string }) => {
|
|||||||
market={marketData}
|
market={marketData}
|
||||||
type="settlementData"
|
type="settlementData"
|
||||||
parentMarket={
|
parentMarket={
|
||||||
isParentSettlementDataEqual ? undefined : parentMarketData
|
isParentSettlementDataEqual
|
||||||
|
? undefined
|
||||||
|
: parentMarketData || undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -184,7 +187,7 @@ export const ProposalMarketData = ({ proposalId }: { proposalId: string }) => {
|
|||||||
parentMarket={
|
parentMarket={
|
||||||
isParentTerminationDataEqual
|
isParentTerminationDataEqual
|
||||||
? undefined
|
? undefined
|
||||||
: parentMarketData
|
: parentMarketData || undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -202,7 +205,7 @@ export const ProposalMarketData = ({ proposalId }: { proposalId: string }) => {
|
|||||||
parentMarket={
|
parentMarket={
|
||||||
isParentSettlementScheduleDataEqual
|
isParentSettlementScheduleDataEqual
|
||||||
? undefined
|
? undefined
|
||||||
: parentMarketData
|
: parentMarketData || undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -216,19 +219,19 @@ export const ProposalMarketData = ({ proposalId }: { proposalId: string }) => {
|
|||||||
<h2 className={marketDataHeaderStyles}>{t('Settlement assets')}</h2>
|
<h2 className={marketDataHeaderStyles}>{t('Settlement assets')}</h2>
|
||||||
<SettlementAssetInfoPanel
|
<SettlementAssetInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
parentMarket={parentMarketData}
|
parentMarket={parentMarketData || undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2 className={marketDataHeaderStyles}>{t('Metadata')}</h2>
|
<h2 className={marketDataHeaderStyles}>{t('Metadata')}</h2>
|
||||||
<MetadataInfoPanel
|
<MetadataInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
parentMarket={parentMarketData}
|
parentMarket={parentMarketData || undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2 className={marketDataHeaderStyles}>{t('Risk model')}</h2>
|
<h2 className={marketDataHeaderStyles}>{t('Risk model')}</h2>
|
||||||
<RiskModelInfoPanel
|
<RiskModelInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
parentMarket={parentMarketData}
|
parentMarket={parentMarketData || undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2 className={marketDataHeaderStyles}>
|
<h2 className={marketDataHeaderStyles}>
|
||||||
@ -236,61 +239,45 @@ export const ProposalMarketData = ({ proposalId }: { proposalId: string }) => {
|
|||||||
</h2>
|
</h2>
|
||||||
<MarginScalingFactorsPanel
|
<MarginScalingFactorsPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
parentMarket={parentMarketData}
|
parentMarket={parentMarketData || undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2 className={marketDataHeaderStyles}>{t('Risk factors')}</h2>
|
<h2 className={marketDataHeaderStyles}>{t('Risk factors')}</h2>
|
||||||
<RiskFactorsInfoPanel
|
<RiskFactorsInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
parentMarket={parentMarketData}
|
parentMarket={parentMarketData || undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{showParentPriceMonitoringBounds &&
|
{showParentPriceMonitoringBounds && (
|
||||||
(
|
// shows bounds for parent market
|
||||||
parentMarketData?.priceMonitoringSettings?.parameters
|
|
||||||
?.triggers || []
|
|
||||||
).map((_, triggerIndex) => (
|
|
||||||
<>
|
|
||||||
<h2 className={marketDataHeaderStyles}>
|
|
||||||
{t(`Parent price monitoring bounds ${triggerIndex + 1}`)}
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<div className="text-vega-dark-300 line-through">
|
|
||||||
<PriceMonitoringBoundsInfoPanel
|
|
||||||
market={parentMarketData}
|
|
||||||
triggerIndex={triggerIndex}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{(
|
|
||||||
marketData.priceMonitoringSettings?.parameters?.triggers || []
|
|
||||||
).map((_, triggerIndex) => (
|
|
||||||
<>
|
<>
|
||||||
<h2 className={marketDataHeaderStyles}>
|
<h2 className={marketDataHeaderStyles}>
|
||||||
{t(`Price monitoring bounds ${triggerIndex + 1}`)}
|
{t('Parent price monitoring bounds')}
|
||||||
</h2>
|
</h2>
|
||||||
|
<div className="text-vega-dark-300 line-through">
|
||||||
<PriceMonitoringBoundsInfoPanel
|
<PriceMonitoringBoundsInfoPanel market={parentMarketData} />
|
||||||
market={marketData}
|
</div>
|
||||||
triggerIndex={triggerIndex}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
))}
|
)}
|
||||||
|
|
||||||
|
<h2 className={marketDataHeaderStyles}>
|
||||||
|
{t('Price monitoring settings')}
|
||||||
|
</h2>
|
||||||
|
<PriceMonitoringSettingsInfoPanel market={marketData} />
|
||||||
|
|
||||||
<h2 className={marketDataHeaderStyles}>
|
<h2 className={marketDataHeaderStyles}>
|
||||||
{t('Liquidity monitoring parameters')}
|
{t('Liquidity monitoring parameters')}
|
||||||
</h2>
|
</h2>
|
||||||
<LiquidityMonitoringParametersInfoPanel
|
<LiquidityMonitoringParametersInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
parentMarket={parentMarketData}
|
parentMarket={parentMarketData || undefined}
|
||||||
/>
|
/>
|
||||||
<h2 className={marketDataHeaderStyles}>
|
<h2 className={marketDataHeaderStyles}>
|
||||||
{t('Liquidity price range')}
|
{t('Liquidity price range')}
|
||||||
</h2>
|
</h2>
|
||||||
<LiquidityPriceRangeInfoPanel
|
<LiquidityPriceRangeInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
parentMarket={parentMarketData}
|
parentMarket={parentMarketData || undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2 className={marketDataHeaderStyles}>
|
<h2 className={marketDataHeaderStyles}>
|
||||||
@ -298,7 +285,7 @@ export const ProposalMarketData = ({ proposalId }: { proposalId: string }) => {
|
|||||||
</h2>
|
</h2>
|
||||||
<LiquiditySLAParametersInfoPanel
|
<LiquiditySLAParametersInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
parentMarket={parentMarketData}
|
parentMarket={parentMarketData || undefined}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -17,17 +17,20 @@ import { type ProposalNode } from './proposal-utils';
|
|||||||
import { Lozenge } from '@vegaprotocol/ui-toolkit';
|
import { Lozenge } from '@vegaprotocol/ui-toolkit';
|
||||||
import { Indicator } from './indicator';
|
import { Indicator } from './indicator';
|
||||||
import { SubHeading } from '../../../../components/heading';
|
import { SubHeading } from '../../../../components/heading';
|
||||||
|
import { determineId } from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
export const ProposalChangeDetails = ({
|
export const ProposalChangeDetails = ({
|
||||||
proposal,
|
proposal,
|
||||||
terms,
|
terms,
|
||||||
restData,
|
restData,
|
||||||
indicator,
|
indicator,
|
||||||
|
termsCount = 0,
|
||||||
}: {
|
}: {
|
||||||
proposal: Proposal | BatchProposal;
|
proposal: Proposal | BatchProposal;
|
||||||
terms: ProposalTermsFieldsFragment;
|
terms: ProposalTermsFieldsFragment;
|
||||||
restData: ProposalNode | null;
|
restData: ProposalNode | null;
|
||||||
indicator?: number;
|
indicator?: number;
|
||||||
|
termsCount?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
let details = null;
|
let details = null;
|
||||||
@ -61,7 +64,18 @@ export const ProposalChangeDetails = ({
|
|||||||
}
|
}
|
||||||
case 'NewMarket': {
|
case 'NewMarket': {
|
||||||
if (proposal.id) {
|
if (proposal.id) {
|
||||||
details = <ProposalMarketData proposalId={proposal.id} />;
|
let marketId = proposal.id;
|
||||||
|
|
||||||
|
// TODO: when https://github.com/vegaprotocol/vega/issues/11005 gets merged
|
||||||
|
// this will need to be updated to loop forward from 0. Right now subProposals
|
||||||
|
// are returned (when using GQL) in the reverse order
|
||||||
|
if (proposal.__typename === 'BatchProposal') {
|
||||||
|
for (let i = termsCount - 1; i >= 0; i--) {
|
||||||
|
marketId = determineId(marketId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
details = <ProposalMarketData marketId={marketId} />;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -69,7 +83,7 @@ export const ProposalChangeDetails = ({
|
|||||||
if (proposal.id) {
|
if (proposal.id) {
|
||||||
details = (
|
details = (
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<ProposalMarketData proposalId={proposal.id} />
|
<ProposalMarketData marketId={proposal.id} />
|
||||||
<ProposalMarketChanges
|
<ProposalMarketChanges
|
||||||
indicator={indicator}
|
indicator={indicator}
|
||||||
marketId={terms.change.marketId}
|
marketId={terms.change.marketId}
|
||||||
|
@ -78,6 +78,7 @@ export const Proposal = ({ proposal, restData }: ProposalProps) => {
|
|||||||
proposal={proposal}
|
proposal={proposal}
|
||||||
terms={p.terms}
|
terms={p.terms}
|
||||||
restData={restData}
|
restData={restData}
|
||||||
|
termsCount={proposal.subProposals?.length}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
@ -61,6 +61,7 @@ const mockConsensusValidators: NodesFragmentFragment[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
jest.mock('@vegaprotocol/environment', () => ({
|
jest.mock('@vegaprotocol/environment', () => ({
|
||||||
|
...jest.requireActual('@vegaprotocol/environment'),
|
||||||
useVegaRelease: jest.fn(),
|
useVegaRelease: jest.fn(),
|
||||||
useVegaReleases: jest.fn(),
|
useVegaReleases: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
@ -3,8 +3,6 @@ export const VALIDATOR_LOGO_MAP: { [key: string]: string } = {
|
|||||||
'https://pbs.twimg.com/profile_images/1586047492629712897/ZVMWBE94_400x400.jpg',
|
'https://pbs.twimg.com/profile_images/1586047492629712897/ZVMWBE94_400x400.jpg',
|
||||||
efbdf943443bd7595e83b0d7e88f37b7932d487d1b94aab3d004997273bb43fc:
|
efbdf943443bd7595e83b0d7e88f37b7932d487d1b94aab3d004997273bb43fc:
|
||||||
'https://pbs.twimg.com/profile_images/1026823609979949057/3e-LCHHm_400x400.jpg',
|
'https://pbs.twimg.com/profile_images/1026823609979949057/3e-LCHHm_400x400.jpg',
|
||||||
'126751c5830b50d39eb85412fb2964f46338cce6946ff455b73f1b1be3f5e8cc':
|
|
||||||
'https://pbs.twimg.com/profile_images/1228627868542029824/9aoaLiIx_400x400.jpg',
|
|
||||||
'43697a3e911d8b70c0ce672adde17a5c38ca8f6a0486bf85ed0546e1b9a82887':
|
'43697a3e911d8b70c0ce672adde17a5c38ca8f6a0486bf85ed0546e1b9a82887':
|
||||||
'https://pbs.twimg.com/profile_images/1352167987478843392/XzX82gIb_400x400.jpg',
|
'https://pbs.twimg.com/profile_images/1352167987478843392/XzX82gIb_400x400.jpg',
|
||||||
ac735acc9ab11cf1d8c59c2df2107e00092b4ac96451cb137a1629af5b66242a:
|
ac735acc9ab11cf1d8c59c2df2107e00092b4ac96451cb137a1629af5b66242a:
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@apply text-2xl text-white uppercase mb-4;
|
@apply text-2xl text-white mb-4;
|
||||||
}
|
}
|
||||||
h2 {
|
h2 {
|
||||||
@apply text-xl text-white mb-4;
|
@apply text-xl text-white mb-4;
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.tom
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.tom
|
||||||
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
||||||
NX_VEGA_NETWORKS={'{"TESTNET":"https://multisig-signer.fairground.wtf","MAINNET":"https://multisig-signer.vega.xyz"}'
|
NX_VEGA_NETWORKS={'{"TESTNET":"https://multisig-signer.fairground.wtf","MAINNET":"https://multisig-signer.vega.xyz"}'
|
||||||
NX_VEGA_ENV=VALIDATOR_TESTNET
|
NX_VEGA_ENV=VALIDATORS_TESTNET
|
||||||
|
@ -21,6 +21,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=true
|
||||||
NX_ISOLATED_MARGIN=true
|
NX_ISOLATED_MARGIN=true
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
NX_METAMASK_SNAPS=true
|
NX_METAMASK_SNAPS=true
|
||||||
|
@ -21,6 +21,8 @@ NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supp
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=false
|
NX_SUCCESSOR_MARKETS=false
|
||||||
NX_STOP_ORDERS=false
|
NX_STOP_ORDERS=false
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=false
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=true
|
||||||
NX_ISOLATED_MARGIN=true
|
NX_ISOLATED_MARGIN=true
|
||||||
# NX_ICEBERG_ORDERS
|
# NX_ICEBERG_ORDERS
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
|
@ -21,6 +21,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=false
|
||||||
NX_ISOLATED_MARGIN=false
|
NX_ISOLATED_MARGIN=false
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
NX_METAMASK_SNAPS=true
|
NX_METAMASK_SNAPS=true
|
||||||
|
@ -21,6 +21,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=true
|
||||||
NX_ISOLATED_MARGIN=true
|
NX_ISOLATED_MARGIN=true
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
|
@ -22,6 +22,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=true
|
||||||
NX_ISOLATED_MARGIN=true
|
NX_ISOLATED_MARGIN=true
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
NX_METAMASK_SNAPS=true
|
NX_METAMASK_SNAPS=true
|
||||||
|
@ -4,7 +4,7 @@ NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
|||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
NX_SENTRY_DSN=https://2ffce43721964aafa78277c50654ece4@o286262.ingest.sentry.io/6300613
|
NX_SENTRY_DSN=https://2ffce43721964aafa78277c50654ece4@o286262.ingest.sentry.io/6300613
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
|
||||||
NX_VEGA_ENV=VALIDATOR_TESTNET
|
NX_VEGA_ENV=VALIDATORS_TESTNET
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks
|
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks
|
||||||
NX_VEGA_NETWORKS={\"MAINNET\":\"https://console.vega.xyz\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\",\"TESTNET\":\"https://console.fairground.wtf\"}
|
NX_VEGA_NETWORKS={\"MAINNET\":\"https://console.vega.xyz\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\",\"TESTNET\":\"https://console.fairground.wtf\"}
|
||||||
NX_VEGA_TOKEN_URL=https://governance.validators-testnet.vega.rocks
|
NX_VEGA_TOKEN_URL=https://governance.validators-testnet.vega.rocks
|
||||||
@ -22,6 +22,7 @@ NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/m
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=true
|
||||||
NX_ISOLATED_MARGIN=true
|
NX_ISOLATED_MARGIN=true
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
|
@ -9,6 +9,10 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
VegaIcon,
|
VegaIcon,
|
||||||
VegaIconNames,
|
VegaIconNames,
|
||||||
|
Tooltip,
|
||||||
|
TradingAnchorButton,
|
||||||
|
Intent,
|
||||||
|
CopyWithTooltip,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { TransferStatus, type Asset } from '@vegaprotocol/types';
|
import { TransferStatus, type Asset } from '@vegaprotocol/types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
@ -17,7 +21,7 @@ import { Table } from '../../components/table';
|
|||||||
import {
|
import {
|
||||||
addDecimalsFormatNumberQuantum,
|
addDecimalsFormatNumberQuantum,
|
||||||
formatNumber,
|
formatNumber,
|
||||||
getDateTimeFormat,
|
removePaginationWrapper,
|
||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import {
|
import {
|
||||||
useTeam,
|
useTeam,
|
||||||
@ -41,10 +45,6 @@ import {
|
|||||||
} from '../../lib/hooks/use-games';
|
} from '../../lib/hooks/use-games';
|
||||||
import { useEpochInfoQuery } from '../../lib/hooks/__generated__/Epoch';
|
import { useEpochInfoQuery } from '../../lib/hooks/__generated__/Epoch';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
import {
|
|
||||||
ActiveRewardCard,
|
|
||||||
DispatchMetricInfo,
|
|
||||||
} from '../../components/rewards-container/active-rewards';
|
|
||||||
import { type MarketMap, useMarketsMapProvider } from '@vegaprotocol/markets';
|
import { type MarketMap, useMarketsMapProvider } from '@vegaprotocol/markets';
|
||||||
import format from 'date-fns/format';
|
import format from 'date-fns/format';
|
||||||
import {
|
import {
|
||||||
@ -52,6 +52,13 @@ import {
|
|||||||
isScopedToTeams,
|
isScopedToTeams,
|
||||||
useRewards,
|
useRewards,
|
||||||
} from '../../lib/hooks/use-rewards';
|
} from '../../lib/hooks/use-rewards';
|
||||||
|
import {
|
||||||
|
ActiveRewardCard,
|
||||||
|
DispatchMetricInfo,
|
||||||
|
} from '../../components/rewards-container/reward-card';
|
||||||
|
import { usePartyProfilesQuery } from '../../components/vega-wallet-connect-button/__generated__/PartyProfiles';
|
||||||
|
|
||||||
|
const formatDate = (date: Date) => format(date, 'yyyy/MM/dd hh:mm:ss');
|
||||||
|
|
||||||
export const CompetitionsTeam = () => {
|
export const CompetitionsTeam = () => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
@ -140,11 +147,25 @@ const TeamPage = ({
|
|||||||
const t = useT();
|
const t = useT();
|
||||||
const [showGames, setShowGames] = useState(true);
|
const [showGames, setShowGames] = useState(true);
|
||||||
|
|
||||||
|
const createdAt = new Date(team.createdAt);
|
||||||
|
|
||||||
|
const closedIndicator = team.closed ? (
|
||||||
|
<div className="border rounded border-vega-clight-300 dark:border-vega-cdark-300 px-1 pt-[1px] flex items-baseline gap-1">
|
||||||
|
<VegaIcon name={VegaIconNames.LOCK} size={10} />
|
||||||
|
<span>{t('Private')}</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="border rounded border-vega-clight-300 dark:border-vega-cdark-300 px-1 pt-[1px] flex items-baseline gap-1">
|
||||||
|
<VegaIcon name={VegaIconNames.GLOBE} size={10} />
|
||||||
|
<span>{t('Public')}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutWithGradient>
|
<LayoutWithGradient>
|
||||||
<header className="flex gap-3 lg:gap-4 pt-5 lg:pt-10">
|
<header className="flex gap-3 lg:gap-4 pt-5 lg:pt-10">
|
||||||
<TeamAvatar teamId={team.teamId} imgUrl={team.avatarUrl} />
|
<TeamAvatar teamId={team.teamId} imgUrl={team.avatarUrl} />
|
||||||
<div className="flex flex-col items-start gap-1 lg:gap-3">
|
<div className="flex flex-col items-start gap-1 lg:gap-2">
|
||||||
<h1
|
<h1
|
||||||
className="calt text-2xl lg:text-3xl xl:text-5xl"
|
className="calt text-2xl lg:text-3xl xl:text-5xl"
|
||||||
data-testid="team-name"
|
data-testid="team-name"
|
||||||
@ -154,6 +175,38 @@ const TeamPage = ({
|
|||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<JoinTeam team={team} partyTeam={partyTeam} refetch={refetch} />
|
<JoinTeam team={team} partyTeam={partyTeam} refetch={refetch} />
|
||||||
<UpdateTeamButton team={team} />
|
<UpdateTeamButton team={team} />
|
||||||
|
{team.teamUrl && team.teamUrl.length > 0 && (
|
||||||
|
<Tooltip description={t("Visit the team's page.")}>
|
||||||
|
<span>
|
||||||
|
<TradingAnchorButton
|
||||||
|
intent={Intent.Info}
|
||||||
|
target="_blank"
|
||||||
|
referrerPolicy="no-referrer"
|
||||||
|
href={team.teamUrl}
|
||||||
|
>
|
||||||
|
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
|
||||||
|
</TradingAnchorButton>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
<CopyWithTooltip
|
||||||
|
description={t('Copy this page url.')}
|
||||||
|
text={globalThis.location.href}
|
||||||
|
>
|
||||||
|
<button className="h-10 w-7">
|
||||||
|
<VegaIcon name={VegaIconNames.COPY} size={16} />
|
||||||
|
</button>
|
||||||
|
</CopyWithTooltip>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2 items-baseline text-xs text-muted font-alpha calt">
|
||||||
|
{closedIndicator}
|
||||||
|
<div className="">
|
||||||
|
{t('Created at')}:{' '}
|
||||||
|
<span className="text-vega-cdark-600 dark:text-vega-clight-600 ">
|
||||||
|
{formatDate(createdAt)}
|
||||||
|
</span>{' '}
|
||||||
|
({t('epoch')}: {team.createdAtEpoch})
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@ -230,118 +283,138 @@ const Games = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table
|
<div className="text-sm">
|
||||||
columns={[
|
<Table
|
||||||
{
|
columns={[
|
||||||
name: 'epoch',
|
{
|
||||||
displayName: t('Epoch'),
|
name: 'epoch',
|
||||||
},
|
displayName: t('Epoch'),
|
||||||
{
|
},
|
||||||
name: 'endtime',
|
{
|
||||||
displayName: t('End time'),
|
name: 'endtime',
|
||||||
},
|
displayName: t('End time'),
|
||||||
{ name: 'type', displayName: t('Type') },
|
},
|
||||||
{
|
{ name: 'type', displayName: t('Type') },
|
||||||
name: 'asset',
|
{
|
||||||
displayName: t('Reward asset'),
|
name: 'asset',
|
||||||
},
|
displayName: t('Reward asset'),
|
||||||
{ name: 'daily', displayName: t('Daily reward amount') },
|
},
|
||||||
{ name: 'rank', displayName: t('Rank') },
|
{ name: 'daily', displayName: t('Daily reward amount') },
|
||||||
{ name: 'amount', displayName: t('Amount earned this epoch') },
|
{ name: 'rank', displayName: t('Rank') },
|
||||||
{ name: 'total', displayName: t('Cumulative amount earned') },
|
{ name: 'amount', displayName: t('Amount earned this epoch') },
|
||||||
{
|
{ name: 'total', displayName: t('Cumulative amount earned') },
|
||||||
name: 'participatingTeams',
|
{
|
||||||
displayName: t('No. of participating teams'),
|
name: 'participatingTeams',
|
||||||
},
|
displayName: t('No. of participating teams'),
|
||||||
{
|
},
|
||||||
name: 'participatingMembers',
|
{
|
||||||
displayName: t('No. of participating members'),
|
name: 'participatingMembers',
|
||||||
},
|
displayName: t('No. of participating members'),
|
||||||
].map((c) => ({ ...c, headerClassName: 'text-left' }))}
|
},
|
||||||
data={games.map((game) => {
|
].map((c) => ({ ...c, headerClassName: 'text-left' }))}
|
||||||
let transfer = transfers?.find((t) => {
|
data={games.map((game) => {
|
||||||
if (!isScopedToTeams(t)) return false;
|
let transfer = transfers?.find((t) => {
|
||||||
|
if (!isScopedToTeams(t)) return false;
|
||||||
|
|
||||||
const idMatch = t.transfer.gameId === game.id;
|
const idMatch = t.transfer.gameId === game.id;
|
||||||
const metricMatch =
|
const metricMatch =
|
||||||
t.transfer.kind.dispatchStrategy?.dispatchMetric ===
|
t.transfer.kind.dispatchStrategy?.dispatchMetric ===
|
||||||
game.team.rewardMetric;
|
game.team.rewardMetric;
|
||||||
|
|
||||||
const start = t.transfer.kind.startEpoch <= game.epoch;
|
const start = t.transfer.kind.startEpoch <= game.epoch;
|
||||||
const end = t.transfer.kind.endEpoch
|
const end = t.transfer.kind.endEpoch
|
||||||
? t.transfer.kind.endEpoch >= game.epoch
|
? t.transfer.kind.endEpoch >= game.epoch
|
||||||
: true;
|
: true;
|
||||||
|
|
||||||
const rejected = t.transfer.status === TransferStatus.STATUS_REJECTED;
|
const rejected =
|
||||||
|
t.transfer.status === TransferStatus.STATUS_REJECTED;
|
||||||
|
|
||||||
return idMatch && metricMatch && start && end && !rejected;
|
return idMatch && metricMatch && start && end && !rejected;
|
||||||
});
|
});
|
||||||
if (!transfer || !isScopedToTeams(transfer)) transfer = undefined;
|
if (!transfer || !isScopedToTeams(transfer)) transfer = undefined;
|
||||||
const asset = transfer?.transfer.asset;
|
const asset = transfer?.transfer.asset;
|
||||||
|
|
||||||
const dailyAmount =
|
const dailyAmount =
|
||||||
asset && transfer
|
asset && transfer
|
||||||
|
? addDecimalsFormatNumberQuantum(
|
||||||
|
transfer.transfer.amount,
|
||||||
|
asset.decimals,
|
||||||
|
asset.quantum
|
||||||
|
)
|
||||||
|
: '-';
|
||||||
|
|
||||||
|
const earnedAmount = asset
|
||||||
? addDecimalsFormatNumberQuantum(
|
? addDecimalsFormatNumberQuantum(
|
||||||
transfer.transfer.amount,
|
game.team.rewardEarned,
|
||||||
asset.decimals,
|
asset.decimals,
|
||||||
asset.quantum
|
asset.quantum
|
||||||
)
|
)
|
||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
const earnedAmount = asset
|
const totalAmount = asset
|
||||||
? addDecimalsFormatNumberQuantum(
|
? addDecimalsFormatNumberQuantum(
|
||||||
game.team.rewardEarned,
|
game.team.totalRewardsEarned,
|
||||||
asset.decimals,
|
asset.decimals,
|
||||||
asset.quantum
|
asset.quantum
|
||||||
)
|
)
|
||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
const totalAmount = asset
|
const assetSymbol = asset ? <RewardAssetCell asset={asset} /> : '-';
|
||||||
? addDecimalsFormatNumberQuantum(
|
|
||||||
game.team.totalRewardsEarned,
|
|
||||||
asset.decimals,
|
|
||||||
asset.quantum
|
|
||||||
)
|
|
||||||
: '-';
|
|
||||||
|
|
||||||
const assetSymbol = asset ? <RewardAssetCell asset={asset} /> : '-';
|
return {
|
||||||
|
id: game.id,
|
||||||
return {
|
amount: dependable(earnedAmount),
|
||||||
id: game.id,
|
asset: dependable(assetSymbol),
|
||||||
amount: dependable(earnedAmount),
|
daily: dependable(dailyAmount),
|
||||||
asset: dependable(assetSymbol),
|
endtime: <EndTimeCell epoch={game.epoch} />,
|
||||||
daily: dependable(dailyAmount),
|
epoch: game.epoch,
|
||||||
endtime: <EndTimeCell epoch={game.epoch} />,
|
participatingMembers: game.numberOfParticipants,
|
||||||
epoch: game.epoch,
|
participatingTeams: game.entities.length,
|
||||||
participatingMembers: game.numberOfParticipants,
|
rank: game.team.rank,
|
||||||
participatingTeams: game.entities.length,
|
total: totalAmount,
|
||||||
rank: game.team.rank,
|
// type: DispatchMetricLabels[game.team.rewardMetric as DispatchMetric],
|
||||||
total: totalAmount,
|
type: dependable(
|
||||||
// type: DispatchMetricLabels[game.team.rewardMetric as DispatchMetric],
|
<GameTypeCell transfer={transfer} allMarkets={allMarkets} />
|
||||||
type: dependable(
|
),
|
||||||
<GameTypeCell transfer={transfer} allMarkets={allMarkets} />
|
};
|
||||||
),
|
})}
|
||||||
};
|
noCollapse={false}
|
||||||
})}
|
/>
|
||||||
noCollapse={false}
|
</div>
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Members = ({ members }: { members?: Member[] }) => {
|
const Members = ({ members }: { members?: Member[] }) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
|
||||||
|
const partyIds = members?.map((m) => m.referee) || [];
|
||||||
|
const { data: profilesData } = usePartyProfilesQuery({
|
||||||
|
variables: {
|
||||||
|
partyIds,
|
||||||
|
},
|
||||||
|
skip: partyIds.length === 0,
|
||||||
|
});
|
||||||
|
const profiles = removePaginationWrapper(
|
||||||
|
profilesData?.partiesProfilesConnection?.edges
|
||||||
|
);
|
||||||
|
|
||||||
if (!members?.length) {
|
if (!members?.length) {
|
||||||
return <p>{t('No members')}</p>;
|
return <p>{t('No members')}</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = orderBy(
|
const data = orderBy(
|
||||||
members.map((m) => ({
|
members.map((m) => ({
|
||||||
referee: <RefereeLink pubkey={m.referee} isCreator={m.isCreator} />,
|
referee: (
|
||||||
|
<RefereeLink
|
||||||
|
pubkey={m.referee}
|
||||||
|
isCreator={m.isCreator}
|
||||||
|
profiles={profiles}
|
||||||
|
/>
|
||||||
|
),
|
||||||
rewards: formatNumber(m.totalQuantumRewards),
|
rewards: formatNumber(m.totalQuantumRewards),
|
||||||
volume: formatNumber(m.totalQuantumVolume),
|
volume: formatNumber(m.totalQuantumVolume),
|
||||||
gamesPlayed: formatNumber(m.totalGamesPlayed),
|
gamesPlayed: formatNumber(m.totalGamesPlayed),
|
||||||
joinedAt: getDateTimeFormat().format(new Date(m.joinedAt)),
|
joinedAt: formatDate(new Date(m.joinedAt)),
|
||||||
joinedAtEpoch: Number(m.joinedAtEpoch),
|
joinedAtEpoch: Number(m.joinedAtEpoch),
|
||||||
})),
|
})),
|
||||||
'joinedAtEpoch',
|
'joinedAtEpoch',
|
||||||
@ -349,45 +422,69 @@ const Members = ({ members }: { members?: Member[] }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table
|
<div className="text-sm">
|
||||||
columns={[
|
<Table
|
||||||
{ name: 'referee', displayName: t('Member ID') },
|
columns={[
|
||||||
{ name: 'rewards', displayName: t('Rewards earned') },
|
{ name: 'referee', displayName: t('Member') },
|
||||||
{ name: 'volume', displayName: t('Total volume') },
|
{ name: 'rewards', displayName: t('Rewards earned') },
|
||||||
{ name: 'gamesPlayed', displayName: t('Games played') },
|
{ name: 'volume', displayName: t('Total volume') },
|
||||||
{
|
{ name: 'gamesPlayed', displayName: t('Games played') },
|
||||||
name: 'joinedAt',
|
{
|
||||||
displayName: t('Joined at'),
|
name: 'joinedAt',
|
||||||
},
|
displayName: t('Joined at'),
|
||||||
{
|
},
|
||||||
name: 'joinedAtEpoch',
|
{
|
||||||
displayName: t('Joined epoch'),
|
name: 'joinedAtEpoch',
|
||||||
},
|
displayName: t('Joined epoch'),
|
||||||
]}
|
},
|
||||||
data={data}
|
]}
|
||||||
noCollapse={true}
|
data={data}
|
||||||
/>
|
noCollapse={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const RefereeLink = ({
|
const RefereeLink = ({
|
||||||
pubkey,
|
pubkey,
|
||||||
isCreator,
|
isCreator,
|
||||||
|
profiles,
|
||||||
}: {
|
}: {
|
||||||
pubkey: string;
|
pubkey: string;
|
||||||
isCreator: boolean;
|
isCreator: boolean;
|
||||||
|
profiles?: { partyId: string; alias: string }[];
|
||||||
}) => {
|
}) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const linkCreator = useLinks(DApp.Explorer);
|
const linkCreator = useLinks(DApp.Explorer);
|
||||||
const link = linkCreator(EXPLORER_PARTIES.replace(':id', pubkey));
|
const link = linkCreator(EXPLORER_PARTIES.replace(':id', pubkey));
|
||||||
|
|
||||||
|
const alias = profiles?.find((p) => p.partyId === pubkey)?.alias;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="flex items-baseline gap-2">
|
||||||
<Link to={link} target="_blank" className="underline underline-offset-4">
|
<Link to={link} target="_blank" className="underline underline-offset-4">
|
||||||
{truncateMiddle(pubkey)}
|
{alias || truncateMiddle(pubkey)}
|
||||||
</Link>{' '}
|
</Link>
|
||||||
<span className="text-muted text-xs">{isCreator ? t('Owner') : ''}</span>
|
{!alias && (
|
||||||
</>
|
<Tooltip
|
||||||
|
description={t(
|
||||||
|
'You can set your pubkey alias by using the key selector in the top right corner.'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<button className="text-muted text-xs">
|
||||||
|
<VegaIcon name={VegaIconNames.QUESTION_MARK} size={14} />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{alias && (
|
||||||
|
<span className="text-muted text-xs">{truncateMiddle(pubkey)}</span>
|
||||||
|
)}
|
||||||
|
{isCreator && (
|
||||||
|
<span className="text-muted text-xs border border-vega-clight-300 dark:border-vega-cdark-300 rounded px-1 py-[1px]">
|
||||||
|
{t('Owner')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -411,15 +508,12 @@ const EndTimeCell = ({ epoch }: { epoch?: number }) => {
|
|||||||
variables: {
|
variables: {
|
||||||
epochId: epoch ? epoch.toString() : undefined,
|
epochId: epoch ? epoch.toString() : undefined,
|
||||||
},
|
},
|
||||||
fetchPolicy: 'cache-and-network',
|
fetchPolicy: 'cache-first',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) return <Loader size="small" />;
|
if (loading) return <Loader size="small" />;
|
||||||
if (data) {
|
if (data) {
|
||||||
return format(
|
return formatDate(new Date(data.epoch.timestamps.expiry));
|
||||||
new Date(data.epoch.timestamps.expiry),
|
|
||||||
'yyyy/MM/dd hh:mm:ss'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -70,6 +70,12 @@ export const JoinButton = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A team cannot be joined (closed) when set as such
|
||||||
|
* and the currently connected pubkey is not whitelisted.
|
||||||
|
*/
|
||||||
|
const isTeamClosed = team.closed && !team.allowList.includes(pubKey || '');
|
||||||
|
|
||||||
if (!pubKey || isReadOnly) {
|
if (!pubKey || isReadOnly) {
|
||||||
return (
|
return (
|
||||||
<Tooltip description={t('Connect your wallet to join the team')}>
|
<Tooltip description={t('Connect your wallet to join the team')}>
|
||||||
@ -79,8 +85,9 @@ export const JoinButton = ({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Party is the creator of a team
|
// Party is the creator of a team
|
||||||
else if (partyTeam && partyTeam.referrer === pubKey) {
|
if (partyTeam && partyTeam.referrer === pubKey) {
|
||||||
// Party is the creator of THIS team
|
// Party is the creator of THIS team
|
||||||
if (partyTeam.teamId === team.teamId) {
|
if (partyTeam.teamId === team.teamId) {
|
||||||
return (
|
return (
|
||||||
@ -105,8 +112,24 @@ export const JoinButton = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Party is in a team, but not this one
|
// Party is in a team, but not this one
|
||||||
else if (partyTeam && partyTeam.teamId !== team.teamId) {
|
if (partyTeam && partyTeam.teamId !== team.teamId) {
|
||||||
|
// This team is closed.
|
||||||
|
if (isTeamClosed) {
|
||||||
|
return (
|
||||||
|
<Tooltip description={t('You cannot join a private team')}>
|
||||||
|
<Button
|
||||||
|
intent={Intent.Primary}
|
||||||
|
data-testid="switch-team-button"
|
||||||
|
disabled={true}
|
||||||
|
>
|
||||||
|
{t('Switch team')}{' '}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// This team is open.
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => onJoin('switch')}
|
onClick={() => onJoin('switch')}
|
||||||
@ -117,8 +140,9 @@ export const JoinButton = ({
|
|||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Joined. Current party is already in this team
|
// Joined. Current party is already in this team
|
||||||
else if (partyTeam && partyTeam.teamId === team.teamId) {
|
if (partyTeam && partyTeam.teamId === team.teamId) {
|
||||||
return (
|
return (
|
||||||
<Button intent={Intent.None} disabled={true}>
|
<Button intent={Intent.None} disabled={true}>
|
||||||
<span className="flex items-center gap-2">
|
<span className="flex items-center gap-2">
|
||||||
@ -131,6 +155,17 @@ export const JoinButton = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This team is closed.
|
||||||
|
if (isTeamClosed) {
|
||||||
|
return (
|
||||||
|
<Tooltip description={t('You cannot join a closed team')}>
|
||||||
|
<Button intent={Intent.Primary} disabled={true}>
|
||||||
|
{t('Join team')}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// This team is open.
|
||||||
return (
|
return (
|
||||||
<Button onClick={() => onJoin('join')} intent={Intent.Primary}>
|
<Button onClick={() => onJoin('join')} intent={Intent.Primary}>
|
||||||
{t('Join team')}
|
{t('Join team')}
|
||||||
|
@ -5,8 +5,8 @@ import type { Market } from '@vegaprotocol/markets';
|
|||||||
import {
|
import {
|
||||||
addDecimalsFormatNumber,
|
addDecimalsFormatNumber,
|
||||||
fromNanoSeconds,
|
fromNanoSeconds,
|
||||||
getExpiryDate,
|
|
||||||
getMarketExpiryDate,
|
getMarketExpiryDate,
|
||||||
|
useExpiryDate,
|
||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import {
|
import {
|
||||||
Last24hPriceChange,
|
Last24hPriceChange,
|
||||||
@ -20,6 +20,7 @@ import {
|
|||||||
useMarketTradingMode,
|
useMarketTradingMode,
|
||||||
useExternalTwap,
|
useExternalTwap,
|
||||||
getQuoteName,
|
getQuoteName,
|
||||||
|
useMarketState,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import { MarketState as State } from '@vegaprotocol/types';
|
import { MarketState as State } from '@vegaprotocol/types';
|
||||||
import { HeaderStat } from '../../components/header';
|
import { HeaderStat } from '../../components/header';
|
||||||
@ -44,6 +45,12 @@ export const MarketHeaderStats = ({ market }: MarketHeaderStatsProps) => {
|
|||||||
const asset = getAsset(market);
|
const asset = getAsset(market);
|
||||||
const quoteUnit = getQuoteName(market);
|
const quoteUnit = getQuoteName(market);
|
||||||
|
|
||||||
|
const dataSourceSpec = market.markPriceConfiguration?.dataSourcesSpec?.[1];
|
||||||
|
const sourceType =
|
||||||
|
dataSourceSpec?.sourceType.__typename === 'DataSourceDefinitionExternal' &&
|
||||||
|
dataSourceSpec?.sourceType.sourceType.__typename === 'EthCallSpec' &&
|
||||||
|
dataSourceSpec?.sourceType.sourceType;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<HeaderStat heading={t('Mark Price')} testId="market-price">
|
<HeaderStat heading={t('Mark Price')} testId="market-price">
|
||||||
@ -61,16 +68,13 @@ export const MarketHeaderStats = ({ market }: MarketHeaderStatsProps) => {
|
|||||||
<HeaderStat heading={t('Volume (24h)')} testId="market-volume">
|
<HeaderStat heading={t('Volume (24h)')} testId="market-volume">
|
||||||
<Last24hVolume
|
<Last24hVolume
|
||||||
marketId={market.id}
|
marketId={market.id}
|
||||||
positionDecimalPlaces={market.positionDecimalPlaces}
|
|
||||||
marketDecimals={market.decimalPlaces}
|
marketDecimals={market.decimalPlaces}
|
||||||
|
positionDecimalPlaces={market.positionDecimalPlaces}
|
||||||
quoteUnit={quoteUnit}
|
quoteUnit={quoteUnit}
|
||||||
/>
|
/>
|
||||||
</HeaderStat>
|
</HeaderStat>
|
||||||
<HeaderStatMarketTradingMode
|
<HeaderStatMarketTradingMode marketId={market.id} />
|
||||||
marketId={market.id}
|
<MarketState marketId={market.id} />
|
||||||
initialTradingMode={market.tradingMode}
|
|
||||||
/>
|
|
||||||
<MarketState market={market} />
|
|
||||||
{asset ? (
|
{asset ? (
|
||||||
<HeaderStat
|
<HeaderStat
|
||||||
heading={t('Settlement asset')}
|
heading={t('Settlement asset')}
|
||||||
@ -127,14 +131,25 @@ export const MarketHeaderStats = ({ market }: MarketHeaderStatsProps) => {
|
|||||||
{t(
|
{t(
|
||||||
'The external time weighted average price (TWAP) received from the data source defined in the data sourcing specification.'
|
'The external time weighted average price (TWAP) received from the data source defined in the data sourcing specification.'
|
||||||
)}
|
)}
|
||||||
{DocsLinks && (
|
<div className="flex flex-col gap-1">
|
||||||
<ExternalLink
|
{DocsLinks && (
|
||||||
href={DocsLinks.ETH_DATA_SOURCES}
|
<ExternalLink
|
||||||
className="mt-2"
|
href={DocsLinks.ETH_DATA_SOURCES}
|
||||||
>
|
className="mt-2"
|
||||||
{t('Find out more')}
|
>
|
||||||
</ExternalLink>
|
{t('Find out more')}
|
||||||
)}
|
</ExternalLink>
|
||||||
|
)}
|
||||||
|
{sourceType && (
|
||||||
|
<ExternalLink
|
||||||
|
data-testid="oracle-spec-links"
|
||||||
|
href={`${VEGA_EXPLORER_URL}/markets/${market.id}/oracles#${sourceType.address}`}
|
||||||
|
className="text-xs my-1"
|
||||||
|
>
|
||||||
|
{t('Oracle specification')}
|
||||||
|
</ExternalLink>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
testId="index-price"
|
testId="index-price"
|
||||||
@ -264,13 +279,13 @@ export const FundingCountdown = ({ marketId }: { marketId: string }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ExpiryLabel = ({ market }: ExpiryLabelProps) => {
|
const ExpiryLabel = ({ market }: ExpiryLabelProps) => {
|
||||||
const content = market.tradableInstrument.instrument.metadata.tags
|
const { data: marketState } = useMarketState(market.id);
|
||||||
? getExpiryDate(
|
const content =
|
||||||
market.tradableInstrument.instrument.metadata.tags,
|
useExpiryDate(
|
||||||
market.marketTimestamps.close,
|
market.tradableInstrument.instrument.metadata.tags,
|
||||||
market.state
|
market.marketTimestamps.close,
|
||||||
)
|
marketState
|
||||||
: '-';
|
) || '-';
|
||||||
return <div data-testid="trading-expiry">{content}</div>;
|
return <div data-testid="trading-expiry">{content}</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -283,6 +298,7 @@ const ExpiryTooltipContent = ({
|
|||||||
market,
|
market,
|
||||||
explorerUrl,
|
explorerUrl,
|
||||||
}: ExpiryTooltipContentProps) => {
|
}: ExpiryTooltipContentProps) => {
|
||||||
|
const { data: state } = useMarketState(market.id);
|
||||||
const t = useT();
|
const t = useT();
|
||||||
if (market.marketTimestamps.close === null) {
|
if (market.marketTimestamps.close === null) {
|
||||||
const oracleId =
|
const oracleId =
|
||||||
@ -298,8 +314,8 @@ const ExpiryTooltipContent = ({
|
|||||||
const isExpired =
|
const isExpired =
|
||||||
metadataExpiryDate &&
|
metadataExpiryDate &&
|
||||||
Date.now() - metadataExpiryDate.valueOf() > 0 &&
|
Date.now() - metadataExpiryDate.valueOf() > 0 &&
|
||||||
(market.state === State.STATE_TRADING_TERMINATED ||
|
(state === State.STATE_TRADING_TERMINATED ||
|
||||||
market.state === State.STATE_SETTLED);
|
state === State.STATE_SETTLED);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section data-testid="expiry-tooltip">
|
<section data-testid="expiry-tooltip">
|
||||||
|
@ -40,7 +40,6 @@ describe('Closed', () => {
|
|||||||
|
|
||||||
const market = createMarketFragment({
|
const market = createMarketFragment({
|
||||||
id: marketId,
|
id: marketId,
|
||||||
state: MarketState.STATE_SETTLED,
|
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
instrument: {
|
instrument: {
|
||||||
metadata: {
|
metadata: {
|
||||||
@ -96,6 +95,7 @@ describe('Closed', () => {
|
|||||||
|
|
||||||
const marketsData = createMarketsDataFragment({
|
const marketsData = createMarketsDataFragment({
|
||||||
__typename: 'MarketData',
|
__typename: 'MarketData',
|
||||||
|
marketState: MarketState.STATE_SETTLED,
|
||||||
market: {
|
market: {
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
id: marketId,
|
id: marketId,
|
||||||
@ -199,13 +199,16 @@ describe('Closed', () => {
|
|||||||
|
|
||||||
it('renders correctly formatted and filtered rows', async () => {
|
it('renders correctly formatted and filtered rows', async () => {
|
||||||
await renderComponent([marketsMock, marketsDataMock, oracleDataMock]);
|
await renderComponent([marketsMock, marketsDataMock, oracleDataMock]);
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getAllByRole('gridcell').length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
const assetSymbol = getAsset(market).symbol;
|
const assetSymbol = getAsset(market).symbol;
|
||||||
|
|
||||||
const cells = screen.getAllByRole('gridcell');
|
const cells = screen.getAllByRole('gridcell');
|
||||||
const expectedValues = [
|
const expectedValues = [
|
||||||
market.tradableInstrument.instrument.code,
|
market.tradableInstrument.instrument.code,
|
||||||
MarketStateMapping[market.state],
|
MarketStateMapping[marketsData.marketState],
|
||||||
'3 days ago',
|
'3 days ago',
|
||||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||||
addDecimalsFormatNumber(marketsData.bestBidPrice, market.decimalPlaces),
|
addDecimalsFormatNumber(marketsData.bestBidPrice, market.decimalPlaces),
|
||||||
@ -224,87 +227,6 @@ describe('Closed', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('only renders settled and terminated markets', async () => {
|
|
||||||
const mixedMarkets = [
|
|
||||||
{
|
|
||||||
// include as settled
|
|
||||||
__typename: 'MarketEdge' as const,
|
|
||||||
node: createMarketFragment({
|
|
||||||
id: 'include-0',
|
|
||||||
state: MarketState.STATE_SETTLED,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// omit this market
|
|
||||||
__typename: 'MarketEdge' as const,
|
|
||||||
node: createMarketFragment({
|
|
||||||
id: 'discard-0',
|
|
||||||
state: MarketState.STATE_SUSPENDED,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// include as terminated
|
|
||||||
__typename: 'MarketEdge' as const,
|
|
||||||
node: createMarketFragment({
|
|
||||||
id: 'include-1',
|
|
||||||
state: MarketState.STATE_TRADING_TERMINATED,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// omit this market
|
|
||||||
__typename: 'MarketEdge' as const,
|
|
||||||
node: createMarketFragment({
|
|
||||||
id: 'discard-1',
|
|
||||||
state: MarketState.STATE_ACTIVE,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const mixedMarketsMock: MockedResponse<MarketsQuery> = {
|
|
||||||
request: {
|
|
||||||
query: MarketsDocument,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
marketsConnection: {
|
|
||||||
__typename: 'MarketConnection',
|
|
||||||
edges: mixedMarkets,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
await renderComponent([mixedMarketsMock, marketsDataMock, oracleDataMock]);
|
|
||||||
|
|
||||||
// check that the number of rows in datagrid is 2
|
|
||||||
const container = within(
|
|
||||||
document.querySelector('.ag-center-cols-container') as HTMLElement
|
|
||||||
);
|
|
||||||
const expectedRows = mixedMarkets.filter((m) => {
|
|
||||||
return [
|
|
||||||
MarketState.STATE_SETTLED,
|
|
||||||
MarketState.STATE_TRADING_TERMINATED,
|
|
||||||
].includes(m.node.state);
|
|
||||||
});
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
// check rows length is correct
|
|
||||||
const rows = container.getAllByRole('row');
|
|
||||||
expect(rows).toHaveLength(expectedRows.length);
|
|
||||||
});
|
|
||||||
|
|
||||||
// check that only included ids are shown
|
|
||||||
const cells = screen
|
|
||||||
.getAllByRole('gridcell')
|
|
||||||
.filter((cell) => cell.getAttribute('col-id') === 'code')
|
|
||||||
.map((cell) => {
|
|
||||||
const marketCode = within(cell).getByTestId('stack-cell-primary');
|
|
||||||
return marketCode.textContent;
|
|
||||||
});
|
|
||||||
expect(cells).toEqual(
|
|
||||||
expectedRows.map((m) => m.node.tradableInstrument.instrument.code)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('display market actions', async () => {
|
it('display market actions', async () => {
|
||||||
// Use market with a successor Id as the actions dropdown will optionally
|
// Use market with a successor Id as the actions dropdown will optionally
|
||||||
// show a link to the successor market
|
// show a link to the successor market
|
||||||
@ -312,8 +234,7 @@ describe('Closed', () => {
|
|||||||
{
|
{
|
||||||
__typename: 'MarketEdge' as const,
|
__typename: 'MarketEdge' as const,
|
||||||
node: createMarketFragment({
|
node: createMarketFragment({
|
||||||
id: 'include-0',
|
id: marketId,
|
||||||
state: MarketState.STATE_SETTLED,
|
|
||||||
successorMarketID: 'successor',
|
successorMarketID: 'successor',
|
||||||
parentMarketID: 'parent',
|
parentMarketID: 'parent',
|
||||||
}),
|
}),
|
||||||
@ -338,31 +259,33 @@ describe('Closed', () => {
|
|||||||
oracleDataMock,
|
oracleDataMock,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const actionCell = screen
|
await waitFor(async () => {
|
||||||
.getAllByRole('gridcell')
|
const actionCell = screen
|
||||||
.find((el) => el.getAttribute('col-id') === 'market-actions');
|
.getAllByRole('gridcell')
|
||||||
|
.find((el) => el.getAttribute('col-id') === 'market-actions');
|
||||||
|
|
||||||
await userEvent.click(
|
await userEvent.click(
|
||||||
within(actionCell as HTMLElement).getByTestId('dropdown-menu')
|
within(actionCell as HTMLElement).getByTestId('dropdown-menu')
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen.getByRole('menuitem', { name: 'Copy Market ID' })
|
screen.getByRole('menuitem', { name: 'Copy Market ID' })
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
expect(
|
expect(
|
||||||
screen.getByRole('menuitem', { name: 'View on Explorer' })
|
screen.getByRole('menuitem', { name: 'View on Explorer' })
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
expect(
|
expect(
|
||||||
screen.getByRole('menuitem', { name: 'View settlement asset details' })
|
screen.getByRole('menuitem', { name: 'View settlement asset details' })
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
expect(
|
expect(
|
||||||
screen.getByRole('menuitem', { name: 'View parent market' })
|
screen.getByRole('menuitem', { name: 'View parent market' })
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
expect(
|
expect(
|
||||||
screen.getByRole('menuitem', { name: 'View successor market' })
|
screen.getByRole('menuitem', { name: 'View successor market' })
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('successor market should be visible', async () => {
|
it('successor market should be visible', async () => {
|
||||||
@ -370,8 +293,7 @@ describe('Closed', () => {
|
|||||||
{
|
{
|
||||||
__typename: 'MarketEdge' as const,
|
__typename: 'MarketEdge' as const,
|
||||||
node: createMarketFragment({
|
node: createMarketFragment({
|
||||||
id: 'include-0',
|
id: marketId,
|
||||||
state: MarketState.STATE_SETTLED,
|
|
||||||
successorMarketID: 'successor',
|
successorMarketID: 'successor',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
@ -15,7 +15,7 @@ import {
|
|||||||
addDecimalsFormatNumber,
|
addDecimalsFormatNumber,
|
||||||
getMarketExpiryDate,
|
getMarketExpiryDate,
|
||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import { closedMarketsWithDataProvider, getAsset } from '@vegaprotocol/markets';
|
import { closedMarketsProvider, getAsset } from '@vegaprotocol/markets';
|
||||||
import type { DataSourceFilterFragment } from '@vegaprotocol/markets';
|
import type { DataSourceFilterFragment } from '@vegaprotocol/markets';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||||
@ -35,7 +35,7 @@ interface Row {
|
|||||||
code: string;
|
code: string;
|
||||||
name: string;
|
name: string;
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
state: MarketState;
|
state?: MarketState;
|
||||||
metadata: string[];
|
metadata: string[];
|
||||||
closeTimestamp: string | null;
|
closeTimestamp: string | null;
|
||||||
bestBidPrice: string | undefined;
|
bestBidPrice: string | undefined;
|
||||||
@ -53,7 +53,7 @@ interface Row {
|
|||||||
|
|
||||||
export const Closed = () => {
|
export const Closed = () => {
|
||||||
const { data: marketData, error } = useDataProvider({
|
const { data: marketData, error } = useDataProvider({
|
||||||
dataProvider: closedMarketsWithDataProvider,
|
dataProvider: closedMarketsProvider,
|
||||||
variables: undefined,
|
variables: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ export const Closed = () => {
|
|||||||
code: instrument.code,
|
code: instrument.code,
|
||||||
name: instrument.name,
|
name: instrument.name,
|
||||||
decimalPlaces: market.decimalPlaces,
|
decimalPlaces: market.decimalPlaces,
|
||||||
state: market.state,
|
state: market.data?.marketState,
|
||||||
metadata: instrument.metadata.tags ?? [],
|
metadata: instrument.metadata.tags ?? [],
|
||||||
closeTimestamp: market.marketTimestamps.close,
|
closeTimestamp: market.marketTimestamps.close,
|
||||||
bestBidPrice: market.data?.bestBidPrice,
|
bestBidPrice: market.data?.bestBidPrice,
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export { ProposalsList } from './proposals-list';
|
@ -6,7 +6,7 @@ import {
|
|||||||
ActionsDropdown,
|
ActionsDropdown,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
||||||
import { useT } from '../use-t';
|
import { useT } from '../../../lib/use-t';
|
||||||
|
|
||||||
export const ProposalActionsDropdown = ({ id }: { id: string }) => {
|
export const ProposalActionsDropdown = ({ id }: { id: string }) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
@ -18,6 +18,7 @@ export const ProposalActionsDropdown = ({ id }: { id: string }) => {
|
|||||||
<Link
|
<Link
|
||||||
href={linkCreator(TOKEN_PROPOSAL.replace(':id', id))}
|
href={linkCreator(TOKEN_PROPOSAL.replace(':id', id))}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
className="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
|
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
|
||||||
{t('View proposal')}
|
{t('View proposal')}
|
@ -1,77 +1,71 @@
|
|||||||
import { render, screen, waitFor, within } from '@testing-library/react';
|
import { render, screen, waitFor, within } from '@testing-library/react';
|
||||||
import merge from 'lodash/merge';
|
|
||||||
import type { MockedResponse } from '@apollo/client/testing';
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
import { ProposalsList } from './proposals-list';
|
import { ProposalsList } from './proposals-list';
|
||||||
import * as Types from '@vegaprotocol/types';
|
import { MarketState } from '@vegaprotocol/types';
|
||||||
import { createProposalListFieldsFragment } from '../../lib/proposals-data-provider/proposals.mock';
|
import {
|
||||||
import type { ProposalsListQuery } from '../../lib';
|
createMarketFragment,
|
||||||
import { ProposalsListDocument } from '../../lib';
|
createMarketsDataFragment,
|
||||||
import type { PartialDeep } from 'type-fest';
|
} from '@vegaprotocol/mock';
|
||||||
|
import {
|
||||||
|
type MarketsQuery,
|
||||||
|
MarketsDocument,
|
||||||
|
type MarketsQueryVariables,
|
||||||
|
type MarketsDataQuery,
|
||||||
|
type MarketsDataQueryVariables,
|
||||||
|
MarketsDataDocument,
|
||||||
|
} from '@vegaprotocol/markets';
|
||||||
|
|
||||||
const parentMarketName = 'Parent Market Name';
|
const parentMarketName = 'Parent Market Name';
|
||||||
const ParentMarketCell = () => <span>{parentMarketName}</span>;
|
const ParentMarketCell = () => <span>{parentMarketName}</span>;
|
||||||
|
|
||||||
describe('ProposalsList', () => {
|
describe('ProposalsList', () => {
|
||||||
const rowContainerSelector = '.ag-center-cols-container';
|
const rowContainerSelector = '.ag-center-cols-container';
|
||||||
|
const market = createMarketFragment();
|
||||||
const createProposalsMock = (override?: PartialDeep<ProposalsListQuery>) => {
|
const marketData = createMarketsDataFragment({
|
||||||
const defaultProposalEdges = [
|
marketState: MarketState.STATE_PROPOSED,
|
||||||
{
|
|
||||||
__typename: 'ProposalEdge' as const,
|
|
||||||
node: createProposalListFieldsFragment({
|
|
||||||
id: 'id-1',
|
|
||||||
state: Types.ProposalState.STATE_OPEN,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
__typename: 'ProposalEdge' as const,
|
|
||||||
node: createProposalListFieldsFragment({
|
|
||||||
id: 'id-2',
|
|
||||||
state: Types.ProposalState.STATE_PASSED,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
__typename: 'ProposalEdge' as const,
|
|
||||||
node: createProposalListFieldsFragment({
|
|
||||||
id: 'id-3',
|
|
||||||
state: Types.ProposalState.STATE_WAITING_FOR_NODE_VOTE,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const data = merge(
|
|
||||||
{
|
|
||||||
proposalsConnection: {
|
|
||||||
__typename: 'ProposalsConnection' as const,
|
|
||||||
edges: defaultProposalEdges,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
override
|
|
||||||
);
|
|
||||||
|
|
||||||
const mock: MockedResponse<ProposalsListQuery> = {
|
|
||||||
request: {
|
|
||||||
query: ProposalsListDocument,
|
|
||||||
variables: {
|
|
||||||
proposalType: Types.ProposalType.TYPE_NEW_MARKET,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return mock;
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be properly rendered', async () => {
|
it('should be properly rendered', async () => {
|
||||||
const mock = createProposalsMock();
|
const marketMock: MockedResponse<MarketsQuery, MarketsQueryVariables> = {
|
||||||
|
request: {
|
||||||
|
query: MarketsDocument,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
marketsConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: market,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const marketDataMock: MockedResponse<
|
||||||
|
MarketsDataQuery,
|
||||||
|
MarketsDataQueryVariables
|
||||||
|
> = {
|
||||||
|
request: {
|
||||||
|
query: MarketsDataDocument,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
marketsConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: { data: marketData },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<MockedProvider mocks={[mock]}>
|
<MockedProvider mocks={[marketMock, marketDataMock]}>
|
||||||
<ProposalsList cellRenderers={{ ParentMarketCell }} />
|
<ProposalsList cellRenderers={{ ParentMarketCell }} />
|
||||||
</MockedProvider>
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
@ -102,37 +96,47 @@ describe('ProposalsList', () => {
|
|||||||
|
|
||||||
expect(await container.findAllByRole('row')).toHaveLength(
|
expect(await container.findAllByRole('row')).toHaveLength(
|
||||||
// @ts-ignore data is mocked
|
// @ts-ignore data is mocked
|
||||||
mock?.result?.data.proposalsConnection.edges.length
|
marketMock?.result?.data.marketsConnection.edges.length
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
container.getAllByRole('gridcell', {
|
container.getAllByRole('gridcell', {
|
||||||
name: (_, element) =>
|
name: (_, element) =>
|
||||||
element.getAttribute('col-id') ===
|
element.getAttribute('col-id') === 'parentMarketID',
|
||||||
'terms.change.successorConfiguration.parentMarketId',
|
|
||||||
})[0]
|
})[0]
|
||||||
).toHaveTextContent(parentMarketName);
|
).toHaveTextContent(parentMarketName);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('empty response should causes no data message display', async () => {
|
it('empty response should causes no data message display', async () => {
|
||||||
const mock: MockedResponse<ProposalsListQuery> = {
|
const marketMock: MockedResponse<MarketsQuery, MarketsQueryVariables> = {
|
||||||
request: {
|
request: {
|
||||||
query: ProposalsListDocument,
|
query: MarketsDocument,
|
||||||
variables: {
|
|
||||||
proposalType: Types.ProposalType.TYPE_NEW_MARKET,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
data: {
|
data: {
|
||||||
proposalsConnection: {
|
marketsConnection: {
|
||||||
__typename: 'ProposalsConnection',
|
edges: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const marketDataMock: MockedResponse<
|
||||||
|
MarketsDataQuery,
|
||||||
|
MarketsDataQueryVariables
|
||||||
|
> = {
|
||||||
|
request: {
|
||||||
|
query: MarketsDataDocument,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
marketsConnection: {
|
||||||
edges: [],
|
edges: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
render(
|
render(
|
||||||
<MockedProvider mocks={[mock]}>
|
<MockedProvider mocks={[marketMock, marketDataMock]}>
|
||||||
<ProposalsList cellRenderers={{ ParentMarketCell }} />
|
<ProposalsList cellRenderers={{ ParentMarketCell }} />
|
||||||
</MockedProvider>
|
</MockedProvider>
|
||||||
);
|
);
|
@ -0,0 +1,37 @@
|
|||||||
|
import type { FC } from 'react';
|
||||||
|
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||||
|
import { useProposedMarketsList } from '@vegaprotocol/markets';
|
||||||
|
import { type ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
||||||
|
import { useColumnDefs } from './use-column-defs';
|
||||||
|
import { useT } from '../../../lib/use-t';
|
||||||
|
|
||||||
|
const defaultColDef = {
|
||||||
|
sortable: true,
|
||||||
|
filter: true,
|
||||||
|
resizable: true,
|
||||||
|
filterParams: { buttons: ['reset'] },
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ProposalListProps {
|
||||||
|
cellRenderers: {
|
||||||
|
[name: string]: FC<{ value: string; data: ProposalListFieldsFragment }>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProposalsList = ({ cellRenderers }: ProposalListProps) => {
|
||||||
|
const t = useT();
|
||||||
|
const { data } = useProposedMarketsList();
|
||||||
|
const columnDefs = useColumnDefs();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AgGrid
|
||||||
|
columnDefs={columnDefs}
|
||||||
|
rowData={data}
|
||||||
|
defaultColDef={defaultColDef}
|
||||||
|
getRowId={({ data }) => data.id}
|
||||||
|
overlayNoRowsTemplate={t('No proposed markets')}
|
||||||
|
components={cellRenderers}
|
||||||
|
rowHeight={45}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -13,12 +13,16 @@ import type {
|
|||||||
VegaValueFormatterParams,
|
VegaValueFormatterParams,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import {
|
import {
|
||||||
ProposalProductTypeShortName,
|
MarketStateMapping,
|
||||||
ProposalStateMapping,
|
ProductTypeMapping,
|
||||||
|
ProductTypeShortName,
|
||||||
} from '@vegaprotocol/types';
|
} from '@vegaprotocol/types';
|
||||||
import type { ProposalListFieldsFragment } from '../../lib/proposals-data-provider/__generated__/Proposals';
|
import { ProposalActionsDropdown } from './proposal-actions-dropdown';
|
||||||
import { ProposalActionsDropdown } from '../proposal-actions-dropdown';
|
import {
|
||||||
import { useT } from '../../use-t';
|
type MarketMaybeWithData,
|
||||||
|
getProductType,
|
||||||
|
} from '@vegaprotocol/markets';
|
||||||
|
import { useT } from '../../../lib/use-t';
|
||||||
|
|
||||||
export const useColumnDefs = () => {
|
export const useColumnDefs = () => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
@ -28,7 +32,7 @@ export const useColumnDefs = () => {
|
|||||||
{
|
{
|
||||||
colId: 'market',
|
colId: 'market',
|
||||||
headerName: t('Market'),
|
headerName: t('Market'),
|
||||||
field: 'terms.change.instrument.code',
|
field: 'tradableInstrument.instrument.code',
|
||||||
pinned: true,
|
pinned: true,
|
||||||
cellStyle: { lineHeight: '14px' },
|
cellStyle: { lineHeight: '14px' },
|
||||||
cellRenderer: ({
|
cellRenderer: ({
|
||||||
@ -36,20 +40,10 @@ export const useColumnDefs = () => {
|
|||||||
data,
|
data,
|
||||||
}: {
|
}: {
|
||||||
value: string;
|
value: string;
|
||||||
data: ProposalListFieldsFragment;
|
data: MarketMaybeWithData;
|
||||||
}) => {
|
}) => {
|
||||||
if (!value || !data) return '-';
|
if (!value || !data) return '-';
|
||||||
|
|
||||||
const getProductType = (data: ProposalListFieldsFragment) => {
|
|
||||||
if (
|
|
||||||
data.terms.__typename === 'ProposalTerms' &&
|
|
||||||
data.terms.change.__typename === 'NewMarket'
|
|
||||||
) {
|
|
||||||
return data.terms.change.instrument.product?.__typename;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
const productType = getProductType(data);
|
const productType = getProductType(data);
|
||||||
return (
|
return (
|
||||||
productType && (
|
productType && (
|
||||||
@ -57,10 +51,10 @@ export const useColumnDefs = () => {
|
|||||||
primary={value}
|
primary={value}
|
||||||
secondary={
|
secondary={
|
||||||
<span
|
<span
|
||||||
title={ProposalProductTypeShortName[productType]}
|
title={ProductTypeMapping[productType]}
|
||||||
className="uppercase"
|
className="uppercase"
|
||||||
>
|
>
|
||||||
{ProposalProductTypeShortName[productType]}
|
{ProductTypeShortName[productType]}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -71,47 +65,53 @@ export const useColumnDefs = () => {
|
|||||||
{
|
{
|
||||||
colId: 'asset',
|
colId: 'asset',
|
||||||
headerName: t('Settlement asset'),
|
headerName: t('Settlement asset'),
|
||||||
field: 'terms.change.instrument.product.settlementAsset.symbol',
|
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colId: 'state',
|
colId: 'state',
|
||||||
headerName: t('State'),
|
headerName: t('State'),
|
||||||
field: 'state',
|
field: 'data.marketState',
|
||||||
valueFormatter: ({
|
valueFormatter: ({
|
||||||
value,
|
value,
|
||||||
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) =>
|
}: VegaValueFormatterParams<
|
||||||
value ? ProposalStateMapping[value] : '-',
|
MarketMaybeWithData,
|
||||||
|
'data.marketState'
|
||||||
|
>) => {
|
||||||
|
return value ? MarketStateMapping[value] : '-';
|
||||||
|
},
|
||||||
filter: SetFilter,
|
filter: SetFilter,
|
||||||
filterParams: {
|
filterParams: {
|
||||||
set: ProposalStateMapping,
|
set: MarketStateMapping,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headerName: t('Parent market'),
|
headerName: t('Parent market'),
|
||||||
field: 'terms.change.successorConfiguration.parentMarketId',
|
field: 'parentMarketID',
|
||||||
cellRenderer: 'ParentMarketCell',
|
cellRenderer: 'ParentMarketCell',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colId: 'closing-date',
|
colId: 'closing-date',
|
||||||
headerName: t('Closing date'),
|
headerName: t('Closing date'),
|
||||||
field: 'terms.closingDatetime',
|
field: 'marketTimestamps.pending',
|
||||||
valueFormatter: ({
|
valueFormatter: ({
|
||||||
value,
|
value,
|
||||||
}: VegaValueFormatterParams<
|
}: VegaValueFormatterParams<
|
||||||
ProposalListFieldsFragment,
|
MarketMaybeWithData,
|
||||||
'terms.closingDatetime'
|
'marketTimestamps.pending'
|
||||||
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
|
>) => {
|
||||||
|
return value ? getDateTimeFormat().format(new Date(value)) : '-';
|
||||||
|
},
|
||||||
filter: DateRangeFilter,
|
filter: DateRangeFilter,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colId: 'enactment-date',
|
colId: 'enactment-date',
|
||||||
headerName: t('Enactment date'),
|
headerName: t('Enactment date'),
|
||||||
field: 'terms.enactmentDatetime',
|
field: 'marketTimestamps.open',
|
||||||
valueFormatter: ({
|
valueFormatter: ({
|
||||||
value,
|
value,
|
||||||
}: VegaValueFormatterParams<
|
}: VegaValueFormatterParams<
|
||||||
ProposalListFieldsFragment,
|
MarketMaybeWithData,
|
||||||
'terms.enactmentDatetime'
|
'marketTimestamps.open'
|
||||||
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
|
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
|
||||||
filter: DateRangeFilter,
|
filter: DateRangeFilter,
|
||||||
},
|
},
|
||||||
@ -120,10 +120,10 @@ export const useColumnDefs = () => {
|
|||||||
...COL_DEFS.actions,
|
...COL_DEFS.actions,
|
||||||
cellRenderer: ({
|
cellRenderer: ({
|
||||||
data,
|
data,
|
||||||
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
|
}: VegaICellRendererParams<MarketMaybeWithData>) => {
|
||||||
if (!data?.id) return null;
|
if (!data?.marketProposal?.id) return null;
|
||||||
|
|
||||||
return <ProposalActionsDropdown id={data.id} />;
|
return <ProposalActionsDropdown id={data.marketProposal.id} />;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
@ -1,4 +1,4 @@
|
|||||||
import { ProposalsList } from '@vegaprotocol/proposals';
|
import { ProposalsList } from './proposals-list';
|
||||||
import { ParentMarketCell } from './parent-market-cell';
|
import { ParentMarketCell } from './parent-market-cell';
|
||||||
|
|
||||||
const cellRenderers = {
|
const cellRenderers = {
|
||||||
|
@ -9,7 +9,7 @@ export interface SettlementDataCellProps {
|
|||||||
oracleSpecId: string;
|
oracleSpecId: string;
|
||||||
metaDate: Date | null;
|
metaDate: Date | null;
|
||||||
closeTimestamp: string | null;
|
closeTimestamp: string | null;
|
||||||
marketState: MarketState;
|
marketState?: MarketState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SettlementDateCell = ({
|
export const SettlementDateCell = ({
|
||||||
|
@ -15,7 +15,6 @@ import {
|
|||||||
import { ButtonLink, Tooltip } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
import type {
|
import type {
|
||||||
MarketFieldsFragment,
|
|
||||||
MarketMaybeWithData,
|
MarketMaybeWithData,
|
||||||
MarketMaybeWithDataAndCandles,
|
MarketMaybeWithDataAndCandles,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
@ -126,7 +125,9 @@ export const useMarketsColumnDefs = () => {
|
|||||||
valueFormatter: ({
|
valueFormatter: ({
|
||||||
data,
|
data,
|
||||||
}: VegaValueFormatterParams<MarketMaybeWithData, 'state'>) => {
|
}: VegaValueFormatterParams<MarketMaybeWithData, 'state'>) => {
|
||||||
return data?.state ? Schema.MarketStateMapping[data.state] : '-';
|
return data?.data?.marketState
|
||||||
|
? Schema.MarketStateMapping[data?.data?.marketState]
|
||||||
|
: '-';
|
||||||
},
|
},
|
||||||
filter: SetFilter,
|
filter: SetFilter,
|
||||||
filterParams: {
|
filterParams: {
|
||||||
@ -166,9 +167,10 @@ export const useMarketsColumnDefs = () => {
|
|||||||
valueFormatter: ({
|
valueFormatter: ({
|
||||||
data,
|
data,
|
||||||
}: ValueFormatterParams<MarketMaybeWithDataAndCandles, 'candles'>) => {
|
}: ValueFormatterParams<MarketMaybeWithDataAndCandles, 'candles'>) => {
|
||||||
const candles = data?.candles;
|
if (!data) return '-';
|
||||||
|
const candles = data.candles;
|
||||||
const vol = candles ? calcCandleVolume(candles) : '0';
|
const vol = candles ? calcCandleVolume(candles) : '0';
|
||||||
const quoteName = getQuoteName(data as MarketFieldsFragment);
|
const quoteName = getQuoteName(data);
|
||||||
const volPrice =
|
const volPrice =
|
||||||
candles &&
|
candles &&
|
||||||
calcCandleVolumePrice(
|
calcCandleVolumePrice(
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import type { InMemoryCacheConfig } from '@apollo/client';
|
import type { InMemoryCacheConfig } from '@apollo/client';
|
||||||
import {
|
import {
|
||||||
AppLoader,
|
|
||||||
NetworkLoader,
|
NetworkLoader,
|
||||||
useEnvironment,
|
useEnvironment,
|
||||||
useNodeSwitcherStore,
|
useNodeSwitcherStore,
|
||||||
@ -86,10 +85,6 @@ export const Bootstrapper = ({ children }: { children: ReactNode }) => {
|
|||||||
}));
|
}));
|
||||||
const config = useVegaWalletConfig();
|
const config = useVegaWalletConfig();
|
||||||
|
|
||||||
if (!config) {
|
|
||||||
return <AppLoader />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ERR_DATA_LOADER = (
|
const ERR_DATA_LOADER = (
|
||||||
<Trans
|
<Trans
|
||||||
i18nKey="It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node."
|
i18nKey="It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node."
|
||||||
@ -118,7 +113,11 @@ export const Bootstrapper = ({ children }: { children: ReactNode }) => {
|
|||||||
skeleton={<Loading />}
|
skeleton={<Loading />}
|
||||||
failure={<Failure reason={t('Could not configure web3 provider')} />}
|
failure={<Failure reason={t('Could not configure web3 provider')} />}
|
||||||
>
|
>
|
||||||
<WalletProvider config={config}>{children}</WalletProvider>
|
{config ? (
|
||||||
|
<WalletProvider config={config}>{children}</WalletProvider>
|
||||||
|
) : (
|
||||||
|
<Failure reason={t('Could not configure the wallet provider')} />
|
||||||
|
)}
|
||||||
</Web3Provider>
|
</Web3Provider>
|
||||||
</DataLoader>
|
</DataLoader>
|
||||||
</NetworkLoader>
|
</NetworkLoader>
|
||||||
@ -145,6 +144,30 @@ const cacheConfig: InMemoryCacheConfig = {
|
|||||||
Product: {
|
Product: {
|
||||||
keyFields: ['settlementAsset', ['id']],
|
keyFields: ['settlementAsset', ['id']],
|
||||||
},
|
},
|
||||||
|
Market: {
|
||||||
|
fields: {
|
||||||
|
/**
|
||||||
|
* Intercept cache field for tickSize because mainnet specific queries have been
|
||||||
|
* set up, marking this field as client only. The following can be removed when mainnet
|
||||||
|
* supports ticksize:
|
||||||
|
*
|
||||||
|
* 1. The typePolicy for tickSize below
|
||||||
|
* 2. The MarketInfoMainnet query in libs/markets/src/lib/components/market-info/MarketInfo.graphql
|
||||||
|
* 3. The ternary to switch queries in libs/markets/src/lib/components/market-info/market-info-data-provider.ts
|
||||||
|
* 4. The MarketsMainnet query in libs/markets/src/lib/markets.graphql
|
||||||
|
* 5. The ternary to switch queries in libs/markets/src/lib/markets-provider.ts
|
||||||
|
*/
|
||||||
|
tickSize: {
|
||||||
|
read(value) {
|
||||||
|
// value is not present, we have probably marked tickSize as a client only field
|
||||||
|
if (!value) return '1';
|
||||||
|
|
||||||
|
// Use fetch response value
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
MarketData: {
|
MarketData: {
|
||||||
keyFields: ['market', ['id']],
|
keyFields: ['market', ['id']],
|
||||||
},
|
},
|
||||||
|
@ -44,6 +44,7 @@ export const CompetitionsLeaderboard = ({
|
|||||||
|
|
||||||
const avatar = (
|
const avatar = (
|
||||||
<TeamAvatar
|
<TeamAvatar
|
||||||
|
key={td.teamId}
|
||||||
teamId={td.teamId}
|
teamId={td.teamId}
|
||||||
imgUrl={td.avatarUrl}
|
imgUrl={td.avatarUrl}
|
||||||
alt={td.name}
|
alt={td.name}
|
||||||
@ -67,7 +68,7 @@ export const CompetitionsLeaderboard = ({
|
|||||||
),
|
),
|
||||||
earned: num(td.totalQuantumRewards),
|
earned: num(td.totalQuantumRewards),
|
||||||
games: num(td.totalGamesPlayed),
|
games: num(td.totalGamesPlayed),
|
||||||
status: td.closed ? t('Closed') : t('Open'),
|
status: td.closed ? t('Private') : t('Public'),
|
||||||
volume: num(td.totalQuantumVolume),
|
volume: num(td.totalQuantumVolume),
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
|
@ -1,6 +1,81 @@
|
|||||||
import { ActiveRewardCard } from '../rewards-container/active-rewards';
|
|
||||||
import { useT } from '../../lib/use-t';
|
import { useT } from '../../lib/use-t';
|
||||||
import { type EnrichedRewardTransfer } from '../../lib/hooks/use-rewards';
|
import { type EnrichedRewardTransfer } from '../../lib/hooks/use-rewards';
|
||||||
|
import { useVegaWallet } from '@vegaprotocol/wallet-react';
|
||||||
|
import { useStakeAvailable } from '../../lib/hooks/use-stake-available';
|
||||||
|
import { useMyTeam } from '../../lib/hooks/use-my-team';
|
||||||
|
import {
|
||||||
|
ActiveRewardCard,
|
||||||
|
areAllMarketsSettled,
|
||||||
|
} from '../rewards-container/reward-card';
|
||||||
|
import {
|
||||||
|
VegaIcon,
|
||||||
|
VegaIconNames,
|
||||||
|
TradingInput,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { type AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||||
|
import { type MarketFieldsFragment } from '@vegaprotocol/markets';
|
||||||
|
import {
|
||||||
|
type TransferNode,
|
||||||
|
DispatchMetricLabels,
|
||||||
|
EntityScopeLabelMapping,
|
||||||
|
AccountType,
|
||||||
|
} from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
export type Filter = {
|
||||||
|
searchTerm: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const applyFilter = (
|
||||||
|
node: TransferNode & {
|
||||||
|
asset?: AssetFieldsFragment | null;
|
||||||
|
markets?: (MarketFieldsFragment | null)[];
|
||||||
|
},
|
||||||
|
filter: Filter
|
||||||
|
) => {
|
||||||
|
const { transfer } = node;
|
||||||
|
|
||||||
|
// if the transfer is a staking reward then it should be displayed
|
||||||
|
if (transfer.toAccountType === AccountType.ACCOUNT_TYPE_GLOBAL_REWARD) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
transfer.kind.__typename !== 'RecurringTransfer' &&
|
||||||
|
transfer.kind.__typename !== 'RecurringGovernanceTransfer'
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(transfer.kind.dispatchStrategy?.dispatchMetric &&
|
||||||
|
DispatchMetricLabels[transfer.kind.dispatchStrategy.dispatchMetric]
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(filter.searchTerm.toLowerCase())) ||
|
||||||
|
transfer.asset?.symbol
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(filter.searchTerm.toLowerCase()) ||
|
||||||
|
(
|
||||||
|
(transfer.kind.dispatchStrategy &&
|
||||||
|
EntityScopeLabelMapping[transfer.kind.dispatchStrategy.entityScope]) ||
|
||||||
|
'Unspecified'
|
||||||
|
)
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(filter.searchTerm.toLowerCase()) ||
|
||||||
|
node.asset?.name
|
||||||
|
.toLocaleLowerCase()
|
||||||
|
.includes(filter.searchTerm.toLowerCase()) ||
|
||||||
|
node.markets?.some((m) =>
|
||||||
|
m?.tradableInstrument?.instrument?.name
|
||||||
|
.toLocaleLowerCase()
|
||||||
|
.includes(filter.searchTerm.toLowerCase())
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
export const GamesContainer = ({
|
export const GamesContainer = ({
|
||||||
data,
|
data,
|
||||||
@ -10,6 +85,23 @@ export const GamesContainer = ({
|
|||||||
currentEpoch: number;
|
currentEpoch: number;
|
||||||
}) => {
|
}) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const { pubKey } = useVegaWallet();
|
||||||
|
const { team } = useMyTeam();
|
||||||
|
const { stakeAvailable, isEligible, requiredStake } = useStakeAvailable();
|
||||||
|
|
||||||
|
const requirements = pubKey
|
||||||
|
? {
|
||||||
|
isEligible,
|
||||||
|
stakeAvailable,
|
||||||
|
requiredStake,
|
||||||
|
team,
|
||||||
|
pubKey,
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const [filter, setFilter] = useState<Filter>({
|
||||||
|
searchTerm: '',
|
||||||
|
});
|
||||||
|
|
||||||
if (!data || data.length === 0) {
|
if (!data || data.length === 0) {
|
||||||
return (
|
return (
|
||||||
@ -20,24 +112,46 @@ export const GamesContainer = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div>
|
||||||
{data.map((game, i) => {
|
{/** CARDS FILTER */}
|
||||||
// TODO: Remove `kind` prop from ActiveRewardCard
|
{data.length > 1 && (
|
||||||
const { transfer } = game;
|
<TradingInput
|
||||||
if (
|
onChange={(e) =>
|
||||||
transfer.kind.__typename !== 'RecurringTransfer' ||
|
setFilter((curr) => ({ ...curr, searchTerm: e.target.value }))
|
||||||
!transfer.kind.dispatchStrategy?.dispatchMetric
|
}
|
||||||
) {
|
value={filter.searchTerm}
|
||||||
return null;
|
type="text"
|
||||||
}
|
placeholder={t(
|
||||||
return (
|
'Search by reward dispatch metric, entity scope or asset name'
|
||||||
<ActiveRewardCard
|
)}
|
||||||
key={i}
|
data-testid="search-term"
|
||||||
transferNode={game}
|
className="mb-4 w-20 mr-2 max-w-xl"
|
||||||
currentEpoch={currentEpoch}
|
prependElement={<VegaIcon name={VegaIconNames.SEARCH} />}
|
||||||
/>
|
/>
|
||||||
);
|
)}
|
||||||
})}
|
{/** CARDS */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{data
|
||||||
|
.filter((n) => applyFilter(n, filter))
|
||||||
|
// filter out the cards (rewards) for which all of the markets
|
||||||
|
// are settled
|
||||||
|
.filter((n) => !areAllMarketsSettled(n))
|
||||||
|
.map((game, i) => {
|
||||||
|
// TODO: Remove `kind` prop from ActiveRewardCard
|
||||||
|
const { transfer } = game;
|
||||||
|
if (!transfer.kind.dispatchStrategy?.dispatchMetric) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<ActiveRewardCard
|
||||||
|
key={i}
|
||||||
|
transferNode={game}
|
||||||
|
currentEpoch={currentEpoch}
|
||||||
|
requirements={requirements}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { isValidUrl } from '@vegaprotocol/utils';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
const NUM_AVATARS = 20;
|
const NUM_AVATARS = 20;
|
||||||
const AVATAR_PATHNAME_PATTERN = '/team-avatars/{id}.png';
|
const AVATAR_PATHNAME_PATTERN = '/team-avatars/{id}.png';
|
||||||
@ -13,26 +11,6 @@ export const getFallbackAvatar = (teamId: string) => {
|
|||||||
return AVATAR_PATHNAME_PATTERN.replace('{id}', avatarId);
|
return AVATAR_PATHNAME_PATTERN.replace('{id}', avatarId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const useAvatar = (teamId: string, url: string) => {
|
|
||||||
const fallback = getFallbackAvatar(teamId);
|
|
||||||
const [avatar, setAvatar] = useState<string>(fallback);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isValidUrl(url)) return;
|
|
||||||
fetch(url, { cache: 'force-cache' })
|
|
||||||
.then((response) => {
|
|
||||||
if (response.ok) {
|
|
||||||
setAvatar(url);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
/** noop */
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return avatar;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const TeamAvatar = ({
|
export const TeamAvatar = ({
|
||||||
teamId,
|
teamId,
|
||||||
imgUrl,
|
imgUrl,
|
||||||
@ -44,11 +22,11 @@ export const TeamAvatar = ({
|
|||||||
alt?: string;
|
alt?: string;
|
||||||
size?: 'large' | 'small';
|
size?: 'large' | 'small';
|
||||||
}) => {
|
}) => {
|
||||||
const img = useAvatar(teamId, imgUrl);
|
// const img = useAvatar(teamId, imgUrl);
|
||||||
return (
|
return (
|
||||||
// eslint-disable-next-line @next/next/no-img-element
|
// eslint-disable-next-line @next/next/no-img-element
|
||||||
<img
|
<img
|
||||||
src={img}
|
src={imgUrl}
|
||||||
alt={alt || 'Team avatar'}
|
alt={alt || 'Team avatar'}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'rounded-full bg-vega-clight-700 dark:bg-vega-cdark-700 shrink-0',
|
'rounded-full bg-vega-clight-700 dark:bg-vega-cdark-700 shrink-0',
|
||||||
@ -58,6 +36,9 @@ export const TeamAvatar = ({
|
|||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
referrerPolicy="no-referrer"
|
referrerPolicy="no-referrer"
|
||||||
|
onError={(e) => {
|
||||||
|
e.currentTarget.src = getFallbackAvatar(teamId);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -115,6 +115,7 @@ describe('MarketSettledBanner', () => {
|
|||||||
open: '100',
|
open: '100',
|
||||||
close: '100',
|
close: '100',
|
||||||
volume: '100',
|
volume: '100',
|
||||||
|
notional: '10000',
|
||||||
periodStart: subHours(new Date(now), 1).toISOString(),
|
periodStart: subHours(new Date(now), 1).toISOString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -125,6 +126,7 @@ describe('MarketSettledBanner', () => {
|
|||||||
open: '100',
|
open: '100',
|
||||||
close: '200',
|
close: '200',
|
||||||
volume: '100',
|
volume: '100',
|
||||||
|
notional: '10000',
|
||||||
periodStart: subHours(new Date(now), 2).toISOString(),
|
periodStart: subHours(new Date(now), 2).toISOString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -161,6 +163,7 @@ describe('MarketSettledBanner', () => {
|
|||||||
open: '100',
|
open: '100',
|
||||||
close: '100',
|
close: '100',
|
||||||
volume: '100',
|
volume: '100',
|
||||||
|
notional: '10000',
|
||||||
periodStart: '2020-01-01T00:00:00',
|
periodStart: '2020-01-01T00:00:00',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -79,6 +79,7 @@ describe('MarketSelectorItem', () => {
|
|||||||
high: '5',
|
high: '5',
|
||||||
low: '5',
|
low: '5',
|
||||||
volume: '50',
|
volume: '50',
|
||||||
|
notional: '10000',
|
||||||
periodStart: yesterday.toISOString(),
|
periodStart: yesterday.toISOString(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -87,6 +88,7 @@ describe('MarketSelectorItem', () => {
|
|||||||
high: '10',
|
high: '10',
|
||||||
low: '10',
|
low: '10',
|
||||||
volume: '50',
|
volume: '50',
|
||||||
|
notional: '10000',
|
||||||
periodStart: yesterday.toISOString(),
|
periodStart: yesterday.toISOString(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -72,17 +72,17 @@ const MarketData = ({
|
|||||||
|
|
||||||
const marketTradingMode = marketData
|
const marketTradingMode = marketData
|
||||||
? marketData.marketTradingMode
|
? marketData.marketTradingMode
|
||||||
: market.data
|
: market.data?.marketTradingMode;
|
||||||
? market.data.marketTradingMode
|
|
||||||
: market.tradingMode;
|
|
||||||
|
|
||||||
const mode = [
|
const mode =
|
||||||
MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
|
marketTradingMode &&
|
||||||
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
[
|
||||||
MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
|
||||||
].includes(marketTradingMode)
|
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||||
? MarketTradingModeMapping[marketTradingMode]
|
MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||||
: '';
|
].includes(marketTradingMode)
|
||||||
|
? MarketTradingModeMapping[marketTradingMode]
|
||||||
|
: '';
|
||||||
|
|
||||||
const { oneDayCandles } = useCandles({ marketId: market.id });
|
const { oneDayCandles } = useCandles({ marketId: market.id });
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ export const MarketSelector = ({
|
|||||||
<div data-testid="market-selector-list">
|
<div data-testid="market-selector-list">
|
||||||
<MarketList
|
<MarketList
|
||||||
data={markets}
|
data={markets}
|
||||||
loading={loading}
|
loading={loading && !data}
|
||||||
error={error}
|
error={error}
|
||||||
searchTerm={filter.searchTerm}
|
searchTerm={filter.searchTerm}
|
||||||
currentMarketId={currentMarketId}
|
currentMarketId={currentMarketId}
|
||||||
|
@ -409,7 +409,6 @@ describe('useMarketSelectorList', () => {
|
|||||||
}),
|
}),
|
||||||
createMarketFragment({
|
createMarketFragment({
|
||||||
id: 'market-1',
|
id: 'market-1',
|
||||||
state: MarketState.STATE_ACTIVE,
|
|
||||||
// @ts-ignore data not on fragment
|
// @ts-ignore data not on fragment
|
||||||
data: createMarketsDataFragment({
|
data: createMarketsDataFragment({
|
||||||
marketState: MarketState.STATE_ACTIVE,
|
marketState: MarketState.STATE_ACTIVE,
|
||||||
@ -424,7 +423,6 @@ describe('useMarketSelectorList', () => {
|
|||||||
}),
|
}),
|
||||||
createMarketFragment({
|
createMarketFragment({
|
||||||
id: 'market-2',
|
id: 'market-2',
|
||||||
state: MarketState.STATE_ACTIVE,
|
|
||||||
// @ts-ignore data not on fragment
|
// @ts-ignore data not on fragment
|
||||||
data: createMarketsDataFragment({
|
data: createMarketsDataFragment({
|
||||||
marketState: MarketState.STATE_ACTIVE,
|
marketState: MarketState.STATE_ACTIVE,
|
||||||
@ -439,7 +437,6 @@ describe('useMarketSelectorList', () => {
|
|||||||
}),
|
}),
|
||||||
createMarketFragment({
|
createMarketFragment({
|
||||||
id: 'market-3',
|
id: 'market-3',
|
||||||
state: MarketState.STATE_ACTIVE,
|
|
||||||
// @ts-ignore data not on fragment
|
// @ts-ignore data not on fragment
|
||||||
data: createMarketsDataFragment({
|
data: createMarketsDataFragment({
|
||||||
marketState: MarketState.STATE_ACTIVE,
|
marketState: MarketState.STATE_ACTIVE,
|
||||||
|
@ -63,7 +63,11 @@ export const useMarketSelectorList = ({
|
|||||||
[
|
[
|
||||||
(m) => {
|
(m) => {
|
||||||
if (!m.candles?.length) return 0;
|
if (!m.candles?.length) return 0;
|
||||||
return Number(priceChangePercentage(m.candles.map((c) => c.close)));
|
return Number(
|
||||||
|
priceChangePercentage(
|
||||||
|
m.candles.filter((c) => c.close !== '').map((c) => c.close)
|
||||||
|
)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[dir]
|
[dir]
|
||||||
|
@ -1,48 +1,18 @@
|
|||||||
import throttle from 'lodash/throttle';
|
import { useMarketState } from '@vegaprotocol/markets';
|
||||||
import type { MarketData, Market } from '@vegaprotocol/markets';
|
|
||||||
import { marketDataProvider } from '@vegaprotocol/markets';
|
|
||||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import { HeaderStat } from '../header';
|
import { HeaderStat } from '../header';
|
||||||
import { useCallback, useRef, useState } from 'react';
|
|
||||||
import * as constants from '../constants';
|
|
||||||
import { DocsLinks } from '@vegaprotocol/environment';
|
import { DocsLinks } from '@vegaprotocol/environment';
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useT } from '../../lib/use-t';
|
import { useT } from '../../lib/use-t';
|
||||||
|
|
||||||
export const MarketState = ({ market }: { market: Market | null }) => {
|
export const MarketState = ({ marketId }: { marketId?: string }) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const [marketState, setMarketState] = useState<Schema.MarketState | null>(
|
const { data: marketState } = useMarketState(marketId);
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
const throttledSetMarketState = useRef(
|
|
||||||
throttle((state: Schema.MarketState) => {
|
|
||||||
setMarketState(state);
|
|
||||||
}, constants.THROTTLE_UPDATE_TIME)
|
|
||||||
).current;
|
|
||||||
|
|
||||||
const update = useCallback(
|
|
||||||
({ data: marketData }: { data: MarketData | null }) => {
|
|
||||||
if (marketData) {
|
|
||||||
throttledSetMarketState(marketData.marketState);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
[throttledSetMarketState]
|
|
||||||
);
|
|
||||||
|
|
||||||
useDataProvider({
|
|
||||||
dataProvider: marketDataProvider,
|
|
||||||
update,
|
|
||||||
variables: { marketId: market?.id || '' },
|
|
||||||
skip: !market?.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderStat
|
<HeaderStat
|
||||||
heading={t('Status')}
|
heading={t('Status')}
|
||||||
description={useGetMarketStateTooltip(marketState)}
|
description={useGetMarketStateTooltip(marketState ?? undefined)}
|
||||||
testId="market-state"
|
testId="market-state"
|
||||||
>
|
>
|
||||||
{marketState ? Schema.MarketStateMapping[marketState] : '-'}
|
{marketState ? Schema.MarketStateMapping[marketState] : '-'}
|
||||||
@ -50,7 +20,7 @@ export const MarketState = ({ market }: { market: Market | null }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const useGetMarketStateTooltip = (state: Schema.MarketState | null) => {
|
const useGetMarketStateTooltip = (state?: Schema.MarketState) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
if (state === Schema.MarketState.STATE_ACTIVE) {
|
if (state === Schema.MarketState.STATE_ACTIVE) {
|
||||||
return t('Enactment date reached and usual auction exit checks pass');
|
return t('Enactment date reached and usual auction exit checks pass');
|
||||||
|
@ -26,20 +26,15 @@ const getTradingModeLabel = (
|
|||||||
interface HeaderStatMarketTradingModeProps {
|
interface HeaderStatMarketTradingModeProps {
|
||||||
marketId?: string;
|
marketId?: string;
|
||||||
onSelect?: (marketId: string, metaKey?: boolean) => void;
|
onSelect?: (marketId: string, metaKey?: boolean) => void;
|
||||||
initialTradingMode?: Schema.MarketTradingMode;
|
|
||||||
initialTrigger?: Schema.AuctionTrigger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HeaderStatMarketTradingMode = ({
|
export const HeaderStatMarketTradingMode = ({
|
||||||
marketId,
|
marketId,
|
||||||
onSelect,
|
onSelect,
|
||||||
initialTradingMode,
|
|
||||||
initialTrigger,
|
|
||||||
}: HeaderStatMarketTradingModeProps) => {
|
}: HeaderStatMarketTradingModeProps) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const { data } = useStaticMarketData(marketId);
|
const { data } = useStaticMarketData(marketId);
|
||||||
const marketTradingMode = data?.marketTradingMode ?? initialTradingMode;
|
const { marketTradingMode, trigger } = data || {};
|
||||||
const trigger = data?.trigger ?? initialTrigger;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderStat
|
<HeaderStat
|
||||||
@ -56,8 +51,6 @@ export const HeaderStatMarketTradingMode = ({
|
|||||||
|
|
||||||
export const MarketTradingMode = ({
|
export const MarketTradingMode = ({
|
||||||
marketId,
|
marketId,
|
||||||
initialTradingMode,
|
|
||||||
initialTrigger,
|
|
||||||
inViewRoot,
|
inViewRoot,
|
||||||
}: Omit<HeaderStatMarketTradingModeProps, 'onUpdate'> & {
|
}: Omit<HeaderStatMarketTradingModeProps, 'onUpdate'> & {
|
||||||
inViewRoot?: RefObject<Element>;
|
inViewRoot?: RefObject<Element>;
|
||||||
@ -72,10 +65,7 @@ export const MarketTradingMode = ({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span ref={ref}>
|
<span ref={ref}>
|
||||||
{getTradingModeLabel(
|
{getTradingModeLabel(data?.marketTradingMode, data?.trigger)}
|
||||||
data?.marketTradingMode ?? initialTradingMode,
|
|
||||||
data?.trigger ?? initialTrigger
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { render, screen, waitFor, within } from '@testing-library/react';
|
import { render, screen, waitFor, within } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { NodeHealthContainer, NodeUrl } from './node-health';
|
import { NodeHealthContainer, NodeUrl } from './node-health';
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
import { MockedProvider, type MockedResponse } from '@apollo/client/testing';
|
||||||
|
import {
|
||||||
|
NodeCheckDocument,
|
||||||
|
type NodeCheckQuery,
|
||||||
|
} from '@vegaprotocol/environment';
|
||||||
|
|
||||||
const mockSetNodeSwitcher = jest.fn();
|
const mockSetNodeSwitcher = jest.fn();
|
||||||
|
|
||||||
@ -15,20 +19,50 @@ jest.mock('@vegaprotocol/environment', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
describe('NodeHealthContainer', () => {
|
describe('NodeHealthContainer', () => {
|
||||||
|
const blockHeight = '1';
|
||||||
|
const nodeCheckMock: MockedResponse<NodeCheckQuery, never> = {
|
||||||
|
request: {
|
||||||
|
query: NodeCheckDocument,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
statistics: {
|
||||||
|
chainId: 'chain-id',
|
||||||
|
blockHeight: blockHeight,
|
||||||
|
vegaTime: '12345',
|
||||||
|
},
|
||||||
|
networkParametersConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'a',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderComponent = (mocks: MockedResponse[] = []) => {
|
||||||
|
return render(
|
||||||
|
<MockedProvider mocks={mocks}>
|
||||||
|
<NodeHealthContainer />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
it('controls the node switcher dialog', async () => {
|
it('controls the node switcher dialog', async () => {
|
||||||
render(<NodeHealthContainer />, { wrapper: MockedProvider });
|
renderComponent([nodeCheckMock]);
|
||||||
await waitFor(() => {
|
expect(await screen.findByRole('button')).toBeInTheDocument();
|
||||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
await userEvent.click(screen.getByRole('button'));
|
await userEvent.click(screen.getByRole('button'));
|
||||||
expect(mockSetNodeSwitcher).toHaveBeenCalled();
|
expect(mockSetNodeSwitcher).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Shows node health data on hover', async () => {
|
it('Shows node health data on hover', async () => {
|
||||||
render(<NodeHealthContainer />, { wrapper: MockedProvider });
|
renderComponent([nodeCheckMock]);
|
||||||
await waitFor(() => {
|
expect(await screen.findByRole('button')).toBeInTheDocument();
|
||||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
await userEvent.hover(screen.getByRole('button'));
|
await userEvent.hover(screen.getByRole('button'));
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
const portal = within(
|
const portal = within(
|
||||||
@ -36,12 +70,13 @@ describe('NodeHealthContainer', () => {
|
|||||||
'[data-radix-popper-content-wrapper]'
|
'[data-radix-popper-content-wrapper]'
|
||||||
) as HTMLElement
|
) as HTMLElement
|
||||||
);
|
);
|
||||||
|
|
||||||
// two tooltips get rendered, I believe for animation purposes
|
// two tooltips get rendered, I believe for animation purposes
|
||||||
const tooltip = within(portal.getAllByTestId('tooltip-content')[0]);
|
const tooltip = within(portal.getAllByTestId('tooltip-content')[0]);
|
||||||
expect(
|
expect(
|
||||||
tooltip.getByRole('link', { name: /^Mainnet status & incidents/ })
|
tooltip.getByRole('link', { name: /^Mainnet status & incidents/ })
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
expect(tooltip.getByText('Non operational')).toBeInTheDocument();
|
expect(tooltip.getByText('Operational')).toBeInTheDocument();
|
||||||
expect(tooltip.getByTitle('Connected node')).toHaveTextContent(
|
expect(tooltip.getByTitle('Connected node')).toHaveTextContent(
|
||||||
'vega-url.wtf'
|
'vega-url.wtf'
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { OrderbookManager } from '@vegaprotocol/market-depth';
|
import { OrderbookManager } from '@vegaprotocol/market-depth';
|
||||||
import { ViewType, useSidebar } from '../sidebar';
|
import { ViewType, useSidebar } from '../sidebar';
|
||||||
import { useDealTicketFormValues } from '@vegaprotocol/deal-ticket';
|
import { useDealTicketFormValues } from '@vegaprotocol/react-helpers';
|
||||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||||
|
|
||||||
export const OrderbookContainer = ({ marketId }: { marketId: string }) => {
|
export const OrderbookContainer = ({ marketId }: { marketId: string }) => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { ActiveRewardCard, applyFilter } from './active-rewards';
|
import { applyFilter } from './active-rewards';
|
||||||
import {
|
import {
|
||||||
AccountType,
|
AccountType,
|
||||||
AssetStatus,
|
AssetStatus,
|
||||||
@ -11,6 +11,17 @@ import {
|
|||||||
type Transfer,
|
type Transfer,
|
||||||
} from '@vegaprotocol/types';
|
} from '@vegaprotocol/types';
|
||||||
import { type EnrichedRewardTransfer } from '../../lib/hooks/use-rewards';
|
import { type EnrichedRewardTransfer } from '../../lib/hooks/use-rewards';
|
||||||
|
import { ActiveRewardCard } from './reward-card';
|
||||||
|
|
||||||
|
jest.mock('../../lib/hooks/__generated__/Rewards', () => ({
|
||||||
|
useTWAPQuery: () => ({
|
||||||
|
data: {
|
||||||
|
timeWeightedNotionalPosition: {
|
||||||
|
timeWeightedNotionalPosition: '1.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
describe('ActiveRewards', () => {
|
describe('ActiveRewards', () => {
|
||||||
const reward: EnrichedRewardTransfer = {
|
const reward: EnrichedRewardTransfer = {
|
||||||
@ -71,7 +82,7 @@ describe('ActiveRewards', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it('renders with valid props', () => {
|
it('renders with valid props', () => {
|
||||||
render(<ActiveRewardCard transferNode={reward} currentEpoch={115432} />);
|
render(<ActiveRewardCard transferNode={reward} currentEpoch={115500} />);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen.getByText(/Liquidity provision fees received/i)
|
screen.getByText(/Liquidity provision fees received/i)
|
||||||
|
@ -1,57 +1,24 @@
|
|||||||
import { useT } from '../../lib/use-t';
|
import { useT } from '../../lib/use-t';
|
||||||
import { addDecimalsFormatNumber, formatNumber } from '@vegaprotocol/utils';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import {
|
import {
|
||||||
type VegaIconSize,
|
|
||||||
Tooltip,
|
|
||||||
VegaIcon,
|
VegaIcon,
|
||||||
VegaIconNames,
|
VegaIconNames,
|
||||||
TradingInput,
|
TradingInput,
|
||||||
TinyScroll,
|
|
||||||
truncateMiddle,
|
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import {
|
import {
|
||||||
type TransferNode,
|
type TransferNode,
|
||||||
DistributionStrategyDescriptionMapping,
|
|
||||||
DistributionStrategyMapping,
|
|
||||||
EntityScope,
|
|
||||||
EntityScopeMapping,
|
|
||||||
DispatchMetric,
|
|
||||||
DispatchMetricDescription,
|
|
||||||
DispatchMetricLabels,
|
DispatchMetricLabels,
|
||||||
EntityScopeLabelMapping,
|
EntityScopeLabelMapping,
|
||||||
MarketState,
|
|
||||||
type DispatchStrategy,
|
|
||||||
IndividualScopeMapping,
|
|
||||||
IndividualScopeDescriptionMapping,
|
|
||||||
AccountType,
|
AccountType,
|
||||||
DistributionStrategy,
|
|
||||||
IndividualScope,
|
|
||||||
type Asset,
|
|
||||||
} from '@vegaprotocol/types';
|
} from '@vegaprotocol/types';
|
||||||
import { Card } from '../card/card';
|
import { Card } from '../card/card';
|
||||||
import { type ReactNode, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import {
|
import { type AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||||
type AssetFieldsFragment,
|
|
||||||
type BasicAssetDetails,
|
|
||||||
} from '@vegaprotocol/assets';
|
|
||||||
import { type MarketFieldsFragment } from '@vegaprotocol/markets';
|
import { type MarketFieldsFragment } from '@vegaprotocol/markets';
|
||||||
import {
|
import { useRewards } from '../../lib/hooks/use-rewards';
|
||||||
type EnrichedRewardTransfer,
|
import { useMyTeam } from '../../lib/hooks/use-my-team';
|
||||||
useRewards,
|
import { useVegaWallet } from '@vegaprotocol/wallet-react';
|
||||||
} from '../../lib/hooks/use-rewards';
|
import { useStakeAvailable } from '../../lib/hooks/use-stake-available';
|
||||||
import compact from 'lodash/compact';
|
import { ActiveRewardCard, areAllMarketsSettled } from './reward-card';
|
||||||
|
|
||||||
enum CardColour {
|
|
||||||
BLUE = 'BLUE',
|
|
||||||
GREEN = 'GREEN',
|
|
||||||
GREY = 'GREY',
|
|
||||||
ORANGE = 'ORANGE',
|
|
||||||
PINK = 'PINK',
|
|
||||||
PURPLE = 'PURPLE',
|
|
||||||
WHITE = 'WHITE',
|
|
||||||
YELLOW = 'YELLOW',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Filter = {
|
export type Filter = {
|
||||||
searchTerm: string;
|
searchTerm: string;
|
||||||
@ -71,7 +38,10 @@ export const applyFilter = (
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transfer.kind.__typename !== 'RecurringTransfer') {
|
if (
|
||||||
|
transfer.kind.__typename !== 'RecurringTransfer' &&
|
||||||
|
transfer.kind.__typename !== 'RecurringGovernanceTransfer'
|
||||||
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +80,18 @@ export const ActiveRewards = ({ currentEpoch }: { currentEpoch: number }) => {
|
|||||||
const { data } = useRewards({
|
const { data } = useRewards({
|
||||||
onlyActive: true,
|
onlyActive: true,
|
||||||
});
|
});
|
||||||
|
const { pubKey } = useVegaWallet();
|
||||||
|
const { team } = useMyTeam();
|
||||||
|
const { stakeAvailable, isEligible, requiredStake } = useStakeAvailable();
|
||||||
|
const requirements = pubKey
|
||||||
|
? {
|
||||||
|
isEligible,
|
||||||
|
stakeAvailable,
|
||||||
|
requiredStake,
|
||||||
|
team,
|
||||||
|
pubKey,
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const [filter, setFilter] = useState<Filter>({
|
const [filter, setFilter] = useState<Filter>({
|
||||||
searchTerm: '',
|
searchTerm: '',
|
||||||
@ -135,713 +117,26 @@ export const ActiveRewards = ({ currentEpoch }: { currentEpoch: number }) => {
|
|||||||
'Search by reward dispatch metric, entity scope or asset name'
|
'Search by reward dispatch metric, entity scope or asset name'
|
||||||
)}
|
)}
|
||||||
data-testid="search-term"
|
data-testid="search-term"
|
||||||
className="mb-4 w-20 mr-2"
|
className="mb-4 w-20 mr-2 max-w-xl"
|
||||||
prependElement={<VegaIcon name={VegaIconNames.SEARCH} />}
|
prependElement={<VegaIcon name={VegaIconNames.SEARCH} />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{/** CARDS */}
|
{/** CARDS */}
|
||||||
<TinyScroll className="grid gap-x-8 gap-y-10 h-fit grid-cols-[repeat(auto-fill,_minmax(230px,_1fr))] md:grid-cols-[repeat(auto-fill,_minmax(230px,_1fr))] lg:grid-cols-[repeat(auto-fill,_minmax(320px,_1fr))] xl:grid-cols-[repeat(auto-fill,_minmax(335px,_1fr))] max-h-[40rem] overflow-auto pr-2">
|
<div className="grid gap-x-8 gap-y-10 h-fit grid-cols-[repeat(auto-fill,_minmax(230px,_1fr))] md:grid-cols-[repeat(auto-fill,_minmax(230px,_1fr))] lg:grid-cols-[repeat(auto-fill,_minmax(320px,_1fr))] xl:grid-cols-[repeat(auto-fill,_minmax(335px,_1fr))] pr-2">
|
||||||
{data
|
{data
|
||||||
.filter((n) => applyFilter(n, filter))
|
.filter((n) => applyFilter(n, filter))
|
||||||
|
// filter out the cards (rewards) for which all of the markets
|
||||||
|
// are settled
|
||||||
|
.filter((n) => !areAllMarketsSettled(n))
|
||||||
.map((node, i) => (
|
.map((node, i) => (
|
||||||
<ActiveRewardCard
|
<ActiveRewardCard
|
||||||
key={i}
|
key={i}
|
||||||
transferNode={node}
|
transferNode={node}
|
||||||
currentEpoch={currentEpoch}
|
currentEpoch={currentEpoch}
|
||||||
|
requirements={requirements}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</TinyScroll>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
type ActiveRewardCardProps = {
|
|
||||||
transferNode: EnrichedRewardTransfer;
|
|
||||||
currentEpoch: number;
|
|
||||||
};
|
|
||||||
export const ActiveRewardCard = ({
|
|
||||||
transferNode,
|
|
||||||
currentEpoch,
|
|
||||||
}: ActiveRewardCardProps) => {
|
|
||||||
// don't display the cards that are scoped to not trading markets
|
|
||||||
const marketSettled = transferNode.markets?.filter(
|
|
||||||
(m) =>
|
|
||||||
m?.state &&
|
|
||||||
[
|
|
||||||
MarketState.STATE_TRADING_TERMINATED,
|
|
||||||
MarketState.STATE_SETTLED,
|
|
||||||
MarketState.STATE_CANCELLED,
|
|
||||||
MarketState.STATE_CLOSED,
|
|
||||||
].includes(m.state)
|
|
||||||
);
|
|
||||||
|
|
||||||
// hide the card if all of the markets are being marked as e.g. settled
|
|
||||||
if (
|
|
||||||
marketSettled?.length === transferNode.markets?.length &&
|
|
||||||
Boolean(transferNode.markets && transferNode.markets.length > 0)
|
|
||||||
) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!transferNode.transfer.kind.dispatchStrategy &&
|
|
||||||
transferNode.transfer.toAccountType ===
|
|
||||||
AccountType.ACCOUNT_TYPE_GLOBAL_REWARD
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
<StakingRewardCard
|
|
||||||
colour={CardColour.WHITE}
|
|
||||||
rewardAmount={addDecimalsFormatNumber(
|
|
||||||
transferNode.transfer.amount,
|
|
||||||
transferNode.transfer.asset?.decimals || 0,
|
|
||||||
6
|
|
||||||
)}
|
|
||||||
rewardAsset={transferNode.transfer.asset || undefined}
|
|
||||||
endsIn={
|
|
||||||
transferNode.transfer.kind.endEpoch != null
|
|
||||||
? transferNode.transfer.kind.endEpoch - currentEpoch
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let colour =
|
|
||||||
DispatchMetricColourMap[
|
|
||||||
transferNode.transfer.kind.dispatchStrategy.dispatchMetric
|
|
||||||
];
|
|
||||||
|
|
||||||
// grey out of any of the markets is suspended or
|
|
||||||
// if the asset is not currently traded on any of the active markets
|
|
||||||
const marketSuspended =
|
|
||||||
transferNode.markets?.filter(
|
|
||||||
(m) =>
|
|
||||||
m?.state === MarketState.STATE_SUSPENDED ||
|
|
||||||
m?.state === MarketState.STATE_SUSPENDED_VIA_GOVERNANCE
|
|
||||||
).length === transferNode.markets?.length &&
|
|
||||||
Boolean(transferNode.markets && transferNode.markets.length > 0);
|
|
||||||
|
|
||||||
if (marketSuspended || !transferNode.isAssetTraded) {
|
|
||||||
colour = CardColour.GREY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RewardCard
|
|
||||||
colour={colour}
|
|
||||||
rewardAmount={addDecimalsFormatNumber(
|
|
||||||
transferNode.transfer.amount,
|
|
||||||
transferNode.transfer.asset?.decimals || 0,
|
|
||||||
6
|
|
||||||
)}
|
|
||||||
rewardAsset={transferNode.dispatchAsset}
|
|
||||||
transferAsset={transferNode.transfer.asset || undefined}
|
|
||||||
endsIn={
|
|
||||||
transferNode.transfer.kind.endEpoch != null
|
|
||||||
? transferNode.transfer.kind.endEpoch - currentEpoch
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
dispatchStrategy={transferNode.transfer.kind.dispatchStrategy}
|
|
||||||
dispatchMetricInfo={<DispatchMetricInfo reward={transferNode} />}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const RewardCard = ({
|
|
||||||
colour,
|
|
||||||
rewardAmount,
|
|
||||||
rewardAsset,
|
|
||||||
transferAsset,
|
|
||||||
vegaAsset,
|
|
||||||
dispatchStrategy,
|
|
||||||
endsIn,
|
|
||||||
dispatchMetricInfo,
|
|
||||||
}: {
|
|
||||||
colour: CardColour;
|
|
||||||
rewardAmount: string;
|
|
||||||
/** The asset linked to the dispatch strategy via `dispatchMetricAssetId` property. */
|
|
||||||
rewardAsset?: BasicAssetDetails;
|
|
||||||
/** The VEGA asset details, required to format the min staking amount. */
|
|
||||||
transferAsset?: Asset | undefined;
|
|
||||||
/** The VEGA asset details, required to format the min staking amount. */
|
|
||||||
vegaAsset?: BasicAssetDetails;
|
|
||||||
/** The transfer's dispatch strategy. */
|
|
||||||
dispatchStrategy: DispatchStrategy;
|
|
||||||
/** The number of epochs until the transfer stops. */
|
|
||||||
endsIn?: number;
|
|
||||||
dispatchMetricInfo?: ReactNode;
|
|
||||||
}) => {
|
|
||||||
const t = useT();
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
'bg-gradient-to-r col-span-full p-0.5 lg:col-auto h-full',
|
|
||||||
'rounded-lg',
|
|
||||||
CardColourStyles[colour].gradientClassName
|
|
||||||
)}
|
|
||||||
data-testid="active-rewards-card"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
CardColourStyles[colour].mainClassName,
|
|
||||||
'bg-gradient-to-b bg-vega-clight-800 dark:bg-vega-cdark-800 h-full w-full rounded-md p-4 flex flex-col gap-4'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="flex justify-between gap-4">
|
|
||||||
{/** ENTITY SCOPE */}
|
|
||||||
<div className="flex flex-col gap-2 items-center text-center">
|
|
||||||
<EntityIcon entityScope={dispatchStrategy.entityScope} />
|
|
||||||
{dispatchStrategy.entityScope && (
|
|
||||||
<span className="text-muted text-xs" data-testid="entity-scope">
|
|
||||||
{EntityScopeLabelMapping[dispatchStrategy.entityScope] ||
|
|
||||||
t('Unspecified')}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/** AMOUNT AND DISTRIBUTION STRATEGY */}
|
|
||||||
<div className="flex flex-col gap-2 items-center text-center">
|
|
||||||
{/** AMOUNT */}
|
|
||||||
<h3 className="flex flex-col gap-1 text-2xl shrink-1 text-center">
|
|
||||||
<span className="font-glitch" data-testid="reward-value">
|
|
||||||
{rewardAmount}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span className="font-alpha" data-testid="reward-asset">
|
|
||||||
{transferAsset?.symbol || ''}
|
|
||||||
</span>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
{/** DISTRIBUTION STRATEGY */}
|
|
||||||
<Tooltip
|
|
||||||
description={t(
|
|
||||||
DistributionStrategyDescriptionMapping[
|
|
||||||
dispatchStrategy.distributionStrategy
|
|
||||||
]
|
|
||||||
)}
|
|
||||||
underline={true}
|
|
||||||
>
|
|
||||||
<span className="text-xs" data-testid="distribution-strategy">
|
|
||||||
{
|
|
||||||
DistributionStrategyMapping[
|
|
||||||
dispatchStrategy.distributionStrategy
|
|
||||||
]
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/** DISTRIBUTION DELAY */}
|
|
||||||
<div className="flex flex-col gap-2 items-center text-center">
|
|
||||||
<CardIcon
|
|
||||||
iconName={VegaIconNames.LOCK}
|
|
||||||
tooltip={t(
|
|
||||||
'Number of epochs after distribution to delay vesting of rewards by'
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
className="text-muted text-xs whitespace-nowrap"
|
|
||||||
data-testid="locked-for"
|
|
||||||
>
|
|
||||||
{t('numberEpochs', '{{count}} epochs', {
|
|
||||||
count: dispatchStrategy.lockPeriod,
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span className="border-[0.5px] dark:border-vega-cdark-500 border-vega-clight-500" />
|
|
||||||
{/** DISPATCH METRIC */}
|
|
||||||
{dispatchMetricInfo ? (
|
|
||||||
dispatchMetricInfo
|
|
||||||
) : (
|
|
||||||
<span data-testid="dispatch-metric-info">
|
|
||||||
{DispatchMetricLabels[dispatchStrategy.dispatchMetric]}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="flex items-center gap-8 flex-wrap">
|
|
||||||
{/** ENDS IN */}
|
|
||||||
{endsIn != null && (
|
|
||||||
<span className="flex flex-col">
|
|
||||||
<span className="text-muted text-xs">{t('Ends in')} </span>
|
|
||||||
<span data-testid="ends-in" data-endsin={endsIn}>
|
|
||||||
{endsIn >= 0
|
|
||||||
? t('numberEpochs', '{{count}} epochs', {
|
|
||||||
count: endsIn,
|
|
||||||
})
|
|
||||||
: t('Ended')}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/** WINDOW LENGTH */}
|
|
||||||
<span className="flex flex-col">
|
|
||||||
<span className="text-muted text-xs">{t('Assessed over')}</span>
|
|
||||||
<span data-testid="assessed-over">
|
|
||||||
{t('numberEpochs', '{{count}} epochs', {
|
|
||||||
count: dispatchStrategy.windowLength,
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/** DISPATCH METRIC DESCRIPTION */}
|
|
||||||
{dispatchStrategy?.dispatchMetric && (
|
|
||||||
<p className="text-muted text-sm h-[3rem]">
|
|
||||||
{t(DispatchMetricDescription[dispatchStrategy?.dispatchMetric])}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<span className="border-[0.5px] dark:border-vega-cdark-500 border-vega-clight-500" />
|
|
||||||
{/** REQUIREMENTS */}
|
|
||||||
{dispatchStrategy && (
|
|
||||||
<RewardRequirements
|
|
||||||
dispatchStrategy={dispatchStrategy}
|
|
||||||
rewardAsset={rewardAsset}
|
|
||||||
vegaAsset={vegaAsset}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const StakingRewardCard = ({
|
|
||||||
colour,
|
|
||||||
rewardAmount,
|
|
||||||
rewardAsset,
|
|
||||||
endsIn,
|
|
||||||
}: {
|
|
||||||
colour: CardColour;
|
|
||||||
rewardAmount: string;
|
|
||||||
/** The asset linked to the dispatch strategy via `dispatchMetricAssetId` property. */
|
|
||||||
rewardAsset?: Asset;
|
|
||||||
/** The number of epochs until the transfer stops. */
|
|
||||||
endsIn?: number;
|
|
||||||
/** The VEGA asset details, required to format the min staking amount. */
|
|
||||||
vegaAsset?: BasicAssetDetails;
|
|
||||||
}) => {
|
|
||||||
const t = useT();
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
'bg-gradient-to-r col-span-full p-0.5 lg:col-auto h-full',
|
|
||||||
'rounded-lg',
|
|
||||||
CardColourStyles[colour].gradientClassName
|
|
||||||
)}
|
|
||||||
data-testid="active-rewards-card"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
CardColourStyles[colour].mainClassName,
|
|
||||||
'bg-gradient-to-b bg-vega-clight-800 dark:bg-vega-cdark-800 h-full w-full rounded-md p-4 flex flex-col gap-4'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="flex justify-between gap-4">
|
|
||||||
{/** ENTITY SCOPE */}
|
|
||||||
<div className="flex flex-col gap-2 items-center text-center">
|
|
||||||
<EntityIcon entityScope={EntityScope.ENTITY_SCOPE_INDIVIDUALS} />
|
|
||||||
{
|
|
||||||
<span className="text-muted text-xs" data-testid="entity-scope">
|
|
||||||
{EntityScopeLabelMapping[
|
|
||||||
EntityScope.ENTITY_SCOPE_INDIVIDUALS
|
|
||||||
] || t('Unspecified')}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/** AMOUNT AND DISTRIBUTION STRATEGY */}
|
|
||||||
<div className="flex flex-col gap-2 items-center text-center">
|
|
||||||
{/** AMOUNT */}
|
|
||||||
<h3 className="flex flex-col gap-1 text-2xl shrink-1 text-center">
|
|
||||||
<span className="font-glitch" data-testid="reward-value">
|
|
||||||
{rewardAmount}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span className="font-alpha">{rewardAsset?.symbol || ''}</span>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
{/** DISTRIBUTION STRATEGY */}
|
|
||||||
<Tooltip
|
|
||||||
description={t(
|
|
||||||
DistributionStrategyDescriptionMapping[
|
|
||||||
DistributionStrategy.DISTRIBUTION_STRATEGY_PRO_RATA
|
|
||||||
]
|
|
||||||
)}
|
|
||||||
underline={true}
|
|
||||||
>
|
|
||||||
<span className="text-xs" data-testid="distribution-strategy">
|
|
||||||
{
|
|
||||||
DistributionStrategyMapping[
|
|
||||||
DistributionStrategy.DISTRIBUTION_STRATEGY_PRO_RATA
|
|
||||||
]
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/** DISTRIBUTION DELAY */}
|
|
||||||
<div className="flex flex-col gap-2 items-center text-center">
|
|
||||||
<CardIcon
|
|
||||||
iconName={VegaIconNames.LOCK}
|
|
||||||
tooltip={t(
|
|
||||||
'Number of epochs after distribution to delay vesting of rewards by'
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
className="text-muted text-xs whitespace-nowrap"
|
|
||||||
data-testid="locked-for"
|
|
||||||
>
|
|
||||||
{t('numberEpochs', '{{count}} epochs', {
|
|
||||||
count: 0,
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span className="border-[0.5px] dark:border-vega-cdark-500 border-vega-clight-500" />
|
|
||||||
{/** DISPATCH METRIC */}
|
|
||||||
{
|
|
||||||
<span data-testid="dispatch-metric-info">
|
|
||||||
{t('Staking rewards')}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
<div className="flex items-center gap-8 flex-wrap">
|
|
||||||
{/** ENDS IN */}
|
|
||||||
{endsIn != null && (
|
|
||||||
<span className="flex flex-col">
|
|
||||||
<span className="text-muted text-xs">{t('Ends in')} </span>
|
|
||||||
<span data-testid="ends-in" data-endsin={endsIn}>
|
|
||||||
{endsIn >= 0
|
|
||||||
? t('numberEpochs', '{{count}} epochs', {
|
|
||||||
count: endsIn,
|
|
||||||
})
|
|
||||||
: t('Ended')}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/** WINDOW LENGTH */}
|
|
||||||
<span className="flex flex-col">
|
|
||||||
<span className="text-muted text-xs">{t('Assessed over')}</span>
|
|
||||||
<span data-testid="assessed-over">
|
|
||||||
{t('numberEpochs', '{{count}} epochs', {
|
|
||||||
count: 1,
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/** DISPATCH METRIC DESCRIPTION */}
|
|
||||||
{
|
|
||||||
<p className="text-muted text-sm h-[3rem]">
|
|
||||||
{t(
|
|
||||||
'Global staking reward for staking $VEGA on the network via the Governance app'
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
}
|
|
||||||
<span className="border-[0.5px] dark:border-vega-cdark-500 border-vega-clight-500" />
|
|
||||||
{/** REQUIREMENTS */}
|
|
||||||
<dl className="flex justify-between flex-wrap items-center gap-3 text-xs">
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<dt className="flex items-center gap-1 text-muted">
|
|
||||||
{t('Team scope')}
|
|
||||||
</dt>
|
|
||||||
<dd className="flex items-center gap-1" data-testid="scope">
|
|
||||||
<Tooltip
|
|
||||||
description={
|
|
||||||
IndividualScopeDescriptionMapping[
|
|
||||||
IndividualScope.INDIVIDUAL_SCOPE_ALL
|
|
||||||
]
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<span>{t('Individual')}</span>
|
|
||||||
</Tooltip>
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<dt className="flex items-center gap-1 text-muted">
|
|
||||||
{t('Staked VEGA')}
|
|
||||||
</dt>
|
|
||||||
<dd
|
|
||||||
className="flex items-center gap-1"
|
|
||||||
data-testid="staking-requirement"
|
|
||||||
>
|
|
||||||
{formatNumber(1, 2)}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<dt className="flex items-center gap-1 text-muted">
|
|
||||||
{t('Average position')}
|
|
||||||
</dt>
|
|
||||||
<dd
|
|
||||||
className="flex items-center gap-1"
|
|
||||||
data-testid="average-position"
|
|
||||||
>
|
|
||||||
{formatNumber(0, 2)}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DispatchMetricInfo = ({
|
|
||||||
reward,
|
|
||||||
}: {
|
|
||||||
reward: EnrichedRewardTransfer;
|
|
||||||
}) => {
|
|
||||||
const t = useT();
|
|
||||||
const dispatchStrategy = reward.transfer.kind.dispatchStrategy;
|
|
||||||
const marketNames = compact(
|
|
||||||
reward.markets?.map((m) => m.tradableInstrument.instrument.name)
|
|
||||||
);
|
|
||||||
|
|
||||||
let additionalDispatchMetricInfo = null;
|
|
||||||
|
|
||||||
// if asset found then display asset symbol
|
|
||||||
if (reward.dispatchAsset) {
|
|
||||||
additionalDispatchMetricInfo = <span>{reward.dispatchAsset.symbol}</span>;
|
|
||||||
}
|
|
||||||
// but if scoped to only one market then display market name
|
|
||||||
if (marketNames.length === 1) {
|
|
||||||
additionalDispatchMetricInfo = <span>{marketNames[0]}</span>;
|
|
||||||
}
|
|
||||||
// or if scoped to many markets then indicate it's scoped to "specific markets"
|
|
||||||
if (marketNames.length > 1) {
|
|
||||||
additionalDispatchMetricInfo = (
|
|
||||||
<Tooltip description={marketNames}>
|
|
||||||
<span>{t('Specific markets')}</span>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span data-testid="dispatch-metric-info">
|
|
||||||
{DispatchMetricLabels[dispatchStrategy.dispatchMetric]}
|
|
||||||
{additionalDispatchMetricInfo != null && (
|
|
||||||
<> • {additionalDispatchMetricInfo}</>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const RewardRequirements = ({
|
|
||||||
dispatchStrategy,
|
|
||||||
rewardAsset,
|
|
||||||
vegaAsset,
|
|
||||||
}: {
|
|
||||||
dispatchStrategy: DispatchStrategy;
|
|
||||||
rewardAsset?: BasicAssetDetails;
|
|
||||||
vegaAsset?: BasicAssetDetails;
|
|
||||||
}) => {
|
|
||||||
const t = useT();
|
|
||||||
|
|
||||||
const entityLabel = EntityScopeLabelMapping[dispatchStrategy.entityScope];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<dl className="flex justify-between flex-wrap items-center gap-3 text-xs">
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<dt className="flex items-center gap-1 text-muted">
|
|
||||||
{entityLabel
|
|
||||||
? t('{{entity}} scope', {
|
|
||||||
entity: entityLabel,
|
|
||||||
})
|
|
||||||
: t('Scope')}
|
|
||||||
</dt>
|
|
||||||
<dd className="flex items-center gap-1" data-testid="scope">
|
|
||||||
<RewardEntityScope dispatchStrategy={dispatchStrategy} />
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<dt className="flex items-center gap-1 text-muted">
|
|
||||||
{t('Staked VEGA')}
|
|
||||||
</dt>
|
|
||||||
<dd
|
|
||||||
className="flex items-center gap-1"
|
|
||||||
data-testid="staking-requirement"
|
|
||||||
>
|
|
||||||
{addDecimalsFormatNumber(
|
|
||||||
dispatchStrategy?.stakingRequirement || 0,
|
|
||||||
vegaAsset?.decimals || 18
|
|
||||||
)}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<dt className="flex items-center gap-1 text-muted">
|
|
||||||
{t('Average position')}
|
|
||||||
</dt>
|
|
||||||
<dd className="flex items-center gap-1" data-testid="average-position">
|
|
||||||
{addDecimalsFormatNumber(
|
|
||||||
dispatchStrategy?.notionalTimeWeightedAveragePositionRequirement ||
|
|
||||||
0,
|
|
||||||
rewardAsset?.decimals || 0
|
|
||||||
)}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
</dl>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const RewardEntityScope = ({
|
|
||||||
dispatchStrategy,
|
|
||||||
}: {
|
|
||||||
dispatchStrategy: DispatchStrategy;
|
|
||||||
}) => {
|
|
||||||
const t = useT();
|
|
||||||
|
|
||||||
if (dispatchStrategy.entityScope === EntityScope.ENTITY_SCOPE_TEAMS) {
|
|
||||||
return (
|
|
||||||
<Tooltip
|
|
||||||
description={
|
|
||||||
dispatchStrategy.teamScope?.length ? (
|
|
||||||
<div className="text-xs">
|
|
||||||
<p className="mb-1">{t('Eligible teams')}</p>
|
|
||||||
<ul>
|
|
||||||
{dispatchStrategy.teamScope.map((teamId) => {
|
|
||||||
if (!teamId) return null;
|
|
||||||
return <li key={teamId}>{truncateMiddle(teamId)}</li>;
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
t('All teams are eligible')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
{dispatchStrategy.teamScope?.length
|
|
||||||
? t('Some teams')
|
|
||||||
: t('All teams')}
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
dispatchStrategy.entityScope === EntityScope.ENTITY_SCOPE_INDIVIDUALS &&
|
|
||||||
dispatchStrategy.individualScope
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
<Tooltip
|
|
||||||
description={
|
|
||||||
IndividualScopeDescriptionMapping[dispatchStrategy.individualScope]
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<span>{IndividualScopeMapping[dispatchStrategy.individualScope]}</span>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return t('Unspecified');
|
|
||||||
};
|
|
||||||
|
|
||||||
const CardColourStyles: Record<
|
|
||||||
CardColour,
|
|
||||||
{ gradientClassName: string; mainClassName: string }
|
|
||||||
> = {
|
|
||||||
[CardColour.BLUE]: {
|
|
||||||
gradientClassName: 'from-vega-blue-500 to-vega-green-400',
|
|
||||||
mainClassName: 'from-vega-blue-400 dark:from-vega-blue-600 to-20%',
|
|
||||||
},
|
|
||||||
[CardColour.GREEN]: {
|
|
||||||
gradientClassName: 'from-vega-green-500 to-vega-yellow-500',
|
|
||||||
mainClassName: 'from-vega-green-400 dark:from-vega-green-600 to-20%',
|
|
||||||
},
|
|
||||||
[CardColour.GREY]: {
|
|
||||||
gradientClassName: 'from-vega-cdark-500 to-vega-clight-200',
|
|
||||||
mainClassName: 'from-vega-cdark-400 dark:from-vega-cdark-600 to-20%',
|
|
||||||
},
|
|
||||||
[CardColour.ORANGE]: {
|
|
||||||
gradientClassName: 'from-vega-orange-500 to-vega-pink-400',
|
|
||||||
mainClassName: 'from-vega-orange-400 dark:from-vega-orange-600 to-20%',
|
|
||||||
},
|
|
||||||
[CardColour.PINK]: {
|
|
||||||
gradientClassName: 'from-vega-pink-500 to-vega-purple-400',
|
|
||||||
mainClassName: 'from-vega-pink-400 dark:from-vega-pink-600 to-20%',
|
|
||||||
},
|
|
||||||
[CardColour.PURPLE]: {
|
|
||||||
gradientClassName: 'from-vega-purple-500 to-vega-blue-400',
|
|
||||||
mainClassName: 'from-vega-purple-400 dark:from-vega-purple-600 to-20%',
|
|
||||||
},
|
|
||||||
[CardColour.WHITE]: {
|
|
||||||
gradientClassName:
|
|
||||||
'from-vega-clight-600 dark:from-vega-clight-900 to-vega-yellow-500 dark:to-vega-yellow-400',
|
|
||||||
mainClassName: 'from-white dark:from-vega-clight-100 to-20%',
|
|
||||||
},
|
|
||||||
[CardColour.YELLOW]: {
|
|
||||||
gradientClassName: 'from-vega-yellow-500 to-vega-orange-400',
|
|
||||||
mainClassName: 'from-vega-yellow-400 dark:from-vega-yellow-600 to-20%',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const DispatchMetricColourMap: Record<DispatchMetric, CardColour> = {
|
|
||||||
// Liquidity provision fees received
|
|
||||||
[DispatchMetric.DISPATCH_METRIC_LP_FEES_RECEIVED]: CardColour.BLUE,
|
|
||||||
// Price maker fees paid
|
|
||||||
[DispatchMetric.DISPATCH_METRIC_MAKER_FEES_PAID]: CardColour.PINK,
|
|
||||||
// Price maker fees earned
|
|
||||||
[DispatchMetric.DISPATCH_METRIC_MAKER_FEES_RECEIVED]: CardColour.GREEN,
|
|
||||||
// Total market value
|
|
||||||
[DispatchMetric.DISPATCH_METRIC_MARKET_VALUE]: CardColour.WHITE,
|
|
||||||
// Average position
|
|
||||||
[DispatchMetric.DISPATCH_METRIC_AVERAGE_POSITION]: CardColour.ORANGE,
|
|
||||||
// Relative return
|
|
||||||
[DispatchMetric.DISPATCH_METRIC_RELATIVE_RETURN]: CardColour.PURPLE,
|
|
||||||
// Return volatility
|
|
||||||
[DispatchMetric.DISPATCH_METRIC_RETURN_VOLATILITY]: CardColour.YELLOW,
|
|
||||||
// Validator ranking
|
|
||||||
[DispatchMetric.DISPATCH_METRIC_VALIDATOR_RANKING]: CardColour.WHITE,
|
|
||||||
};
|
|
||||||
|
|
||||||
const CardIcon = ({
|
|
||||||
size = 18,
|
|
||||||
iconName,
|
|
||||||
tooltip,
|
|
||||||
}: {
|
|
||||||
size?: VegaIconSize;
|
|
||||||
iconName: VegaIconNames;
|
|
||||||
tooltip: string;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Tooltip description={<span>{tooltip}</span>}>
|
|
||||||
<span className="flex items-center p-2 rounded-full border border-gray-600">
|
|
||||||
<VegaIcon name={iconName} size={size} />
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const EntityScopeIconMap: Record<EntityScope, VegaIconNames> = {
|
|
||||||
[EntityScope.ENTITY_SCOPE_TEAMS]: VegaIconNames.TEAM,
|
|
||||||
[EntityScope.ENTITY_SCOPE_INDIVIDUALS]: VegaIconNames.MAN,
|
|
||||||
};
|
|
||||||
|
|
||||||
const EntityIcon = ({
|
|
||||||
entityScope,
|
|
||||||
size = 18,
|
|
||||||
}: {
|
|
||||||
entityScope: EntityScope;
|
|
||||||
size?: VegaIconSize;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Tooltip
|
|
||||||
description={
|
|
||||||
entityScope ? <span>{EntityScopeMapping[entityScope]}</span> : undefined
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<span className="flex items-center p-2 rounded-full border border-gray-600">
|
|
||||||
<VegaIcon
|
|
||||||
name={EntityScopeIconMap[entityScope] || VegaIconNames.QUESTION_MARK}
|
|
||||||
size={size}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
import { usePayoutPerRank } from './rank-table';
|
||||||
|
|
||||||
|
// Test case as per https://docs.google.com/spreadsheets/d/1RpWKnGEf4eYMxjI-feauRa9vWz3pNGdP05ejQrwWatg/
|
||||||
|
describe('usePayoutPerRank', () => {
|
||||||
|
it('should return payouts per person', () => {
|
||||||
|
const rankTable = [
|
||||||
|
{
|
||||||
|
startRank: 1,
|
||||||
|
shareRatio: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startRank: 2,
|
||||||
|
shareRatio: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startRank: 5,
|
||||||
|
shareRatio: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startRank: 10,
|
||||||
|
shareRatio: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startRank: 20,
|
||||||
|
shareRatio: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = usePayoutPerRank(rankTable);
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
numPayouts: [1, 3, 5, 10, 0],
|
||||||
|
ratioShares: [10, 15, 25, 30, 0],
|
||||||
|
payoutsPerTier: [0.125, 0.1875, 0.3125, 0.375, 0],
|
||||||
|
payoutsPerWinner: [0.125, 0.0625, 0.0625, 0.0375],
|
||||||
|
payoutsPerWinnerAsPercentage: [12.5, 6.25, 6.25, 3.75],
|
||||||
|
endRanks: [2, 5, 10, 20],
|
||||||
|
startRanks: [1, 2, 5, 10, 20],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
184
apps/trading/components/rewards-container/rank-table.tsx
Normal file
184
apps/trading/components/rewards-container/rank-table.tsx
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
import type { RankTable } from '@vegaprotocol/types';
|
||||||
|
import { formatNumber } from '@vegaprotocol/utils';
|
||||||
|
import { useT } from '../../lib/use-t';
|
||||||
|
|
||||||
|
export const RankPayoutTable = ({
|
||||||
|
rankTable,
|
||||||
|
}: {
|
||||||
|
rankTable: (RankTable | null)[] | null;
|
||||||
|
}) => {
|
||||||
|
const t = useT();
|
||||||
|
const { payoutsPerWinnerAsPercentage, numPayouts, endRanks } =
|
||||||
|
usePayoutPerRank(rankTable);
|
||||||
|
let isOpenFinalTier = false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
rankTable &&
|
||||||
|
rankTable.length > 0 && (
|
||||||
|
<>
|
||||||
|
<table className="min-w-full divide-y divide-gray-200">
|
||||||
|
<thead className="">
|
||||||
|
<tr className="text-right text-xs divide-x">
|
||||||
|
<th scope="col">
|
||||||
|
<span className="flex p-1 w-full justify-end">
|
||||||
|
{t('Rank tier')}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th scope="col">
|
||||||
|
<span className="flex p-1 w-full justify-end">
|
||||||
|
{t('Start rank')}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th scope="col">
|
||||||
|
<span className="flex p-1 w-full justify-end">
|
||||||
|
{t('End rank')}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th scope="col">
|
||||||
|
<span className="flex p-1 w-full justify-end">
|
||||||
|
{t('Places paid')}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th scope="col">
|
||||||
|
<span className="flex p-1 w-full justify-end">
|
||||||
|
{t('Payout')}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="divide-y divide-gray-500 text-xs">
|
||||||
|
{rankTable?.map((rank: RankTable | null, tier: number) => {
|
||||||
|
const endRank = endRanks?.[tier];
|
||||||
|
const placesPaid = numPayouts?.[tier];
|
||||||
|
const isFinalTier = tier === rankTable.length - 1;
|
||||||
|
isOpenFinalTier =
|
||||||
|
isFinalTier && rank ? rank.shareRatio > 0 : false;
|
||||||
|
|
||||||
|
if (isFinalTier && rank?.shareRatio === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
rank && (
|
||||||
|
<tr
|
||||||
|
key={`rank-table-row-${tier}`}
|
||||||
|
className="whitespace-nowrap text-right divide-x p-4"
|
||||||
|
>
|
||||||
|
<td>
|
||||||
|
<span className="flex p-1 justify-end">{tier + 1}</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span className="flex p-1 justify-end">
|
||||||
|
{rank.startRank}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span className="flex p-1 justify-end">
|
||||||
|
{endRank || 'TBC*'}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span className="flex p-1 justify-end">
|
||||||
|
{placesPaid || 'TBC*'}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span className="flex p-1 justify-end">
|
||||||
|
{payoutsPerWinnerAsPercentage?.[tier]
|
||||||
|
? `${formatNumber(
|
||||||
|
payoutsPerWinnerAsPercentage[tier],
|
||||||
|
2
|
||||||
|
)} %`
|
||||||
|
: 'TBC*'}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
{isOpenFinalTier &&
|
||||||
|
t(
|
||||||
|
'*Note: Final tier will payout to all game participants, therefore all payout estimates will lower depending on how many participants there are.'
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use rank table to calculate payouts per rank
|
||||||
|
// as per https://docs.google.com/spreadsheets/d/1RpWKnGEf4eYMxjI-feauRa9vWz3pNGdP05ejQrwWatg/
|
||||||
|
export const usePayoutPerRank = (
|
||||||
|
rankTable?: (RankTable | null)[] | null
|
||||||
|
): {
|
||||||
|
numPayouts?: number[];
|
||||||
|
startRanks?: number[];
|
||||||
|
endRanks?: number[];
|
||||||
|
ratioShares?: number[];
|
||||||
|
payoutsPerTier?: number[];
|
||||||
|
payoutsPerWinner?: number[];
|
||||||
|
payoutsPerWinnerAsPercentage?: number[];
|
||||||
|
} => {
|
||||||
|
if (!rankTable) return {};
|
||||||
|
|
||||||
|
const numPayouts: number[] = [],
|
||||||
|
ratioShares: number[] = [],
|
||||||
|
startRanks: number[] = [],
|
||||||
|
endRanks: number[] = [],
|
||||||
|
payoutsPerTier: number[] = [],
|
||||||
|
payoutsPerWinner: number[] = [],
|
||||||
|
payoutsPerWinnerAsPercentage: number[] = [];
|
||||||
|
|
||||||
|
let totalRatio = 0;
|
||||||
|
|
||||||
|
// We have to work out how many ppl in each bucket to get the total for the ratio
|
||||||
|
rankTable.forEach((rank, tier) => {
|
||||||
|
const startRank = rank?.startRank;
|
||||||
|
startRank && startRanks.push(startRank);
|
||||||
|
const endRank =
|
||||||
|
tier < rankTable.length - 1 ? rankTable[tier + 1]?.startRank : undefined;
|
||||||
|
endRank && endRanks.push(endRank);
|
||||||
|
const numPayout = endRank && startRank ? endRank - startRank : 0;
|
||||||
|
|
||||||
|
numPayouts.push(numPayout);
|
||||||
|
|
||||||
|
const shareRatio = rank?.shareRatio;
|
||||||
|
const ratioShare = shareRatio ? shareRatio * numPayout : 0;
|
||||||
|
|
||||||
|
ratioShares.push(ratioShare);
|
||||||
|
|
||||||
|
totalRatio += ratioShare;
|
||||||
|
});
|
||||||
|
|
||||||
|
rankTable.forEach((_rank, tier) => {
|
||||||
|
const ratioShare = ratioShares[tier];
|
||||||
|
|
||||||
|
// Then we multiply back out to get the total payout per tier
|
||||||
|
const payoutPerTierValue = totalRatio ? ratioShare / totalRatio : 0;
|
||||||
|
payoutsPerTier.push(payoutPerTierValue);
|
||||||
|
|
||||||
|
const numPayout = numPayouts[tier];
|
||||||
|
|
||||||
|
// And then divide by the payouts to get each individual winner payout
|
||||||
|
const payoutPerWinnerValue =
|
||||||
|
numPayout && payoutPerTierValue
|
||||||
|
? payoutPerTierValue / numPayout
|
||||||
|
: undefined;
|
||||||
|
payoutPerWinnerValue && payoutsPerWinner.push(payoutPerWinnerValue);
|
||||||
|
|
||||||
|
payoutPerWinnerValue &&
|
||||||
|
payoutsPerWinnerAsPercentage.push(payoutPerWinnerValue * 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
numPayouts,
|
||||||
|
ratioShares,
|
||||||
|
startRanks,
|
||||||
|
endRanks,
|
||||||
|
payoutsPerTier,
|
||||||
|
payoutsPerWinner,
|
||||||
|
payoutsPerWinnerAsPercentage,
|
||||||
|
};
|
||||||
|
};
|
1057
apps/trading/components/rewards-container/reward-card.tsx
Normal file
1057
apps/trading/components/rewards-container/reward-card.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@ -246,6 +246,19 @@ export const RewardsContainer = () => {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="grid auto-rows-min grid-cols-6 gap-3">
|
<div className="grid auto-rows-min grid-cols-6 gap-3">
|
||||||
|
<Card
|
||||||
|
title={t('Rewards history')}
|
||||||
|
className="lg:col-span-full hidden md:block"
|
||||||
|
loading={rewardsLoading}
|
||||||
|
noBackgroundOnMobile={true}
|
||||||
|
highlight={true}
|
||||||
|
>
|
||||||
|
<RewardsHistoryContainer
|
||||||
|
epoch={Number(epochData?.epoch.id)}
|
||||||
|
pubKey={pubKey}
|
||||||
|
assets={assetMap}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
{pubKey && activityStreakBenefitTiers.tiers?.length > 0 && (
|
{pubKey && activityStreakBenefitTiers.tiers?.length > 0 && (
|
||||||
<Card
|
<Card
|
||||||
title={t('Activity Streak')}
|
title={t('Activity Streak')}
|
||||||
@ -287,24 +300,12 @@ export const RewardsContainer = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
<ActiveRewards currentEpoch={Number(epochData?.epoch.id)} />
|
<ActiveRewards currentEpoch={Number(epochData?.epoch.id)} />
|
||||||
<Card
|
|
||||||
title={t('Rewards history')}
|
|
||||||
className="lg:col-span-full hidden md:block"
|
|
||||||
loading={rewardsLoading}
|
|
||||||
noBackgroundOnMobile={true}
|
|
||||||
>
|
|
||||||
<RewardsHistoryContainer
|
|
||||||
epoch={Number(epochData?.epoch.id)}
|
|
||||||
pubKey={pubKey}
|
|
||||||
assets={assetMap}
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
type VestingBalances = NonNullable<
|
export type VestingBalances = NonNullable<
|
||||||
RewardsPageQuery['party']
|
RewardsPageQuery['party']
|
||||||
>['vestingBalancesSummary'];
|
>['vestingBalancesSummary'];
|
||||||
|
|
||||||
|
@ -96,6 +96,7 @@ export const VegaWalletConnectButton = ({
|
|||||||
pubKeys={pubKeys}
|
pubKeys={pubKeys}
|
||||||
activeKey={activeKey?.publicKey}
|
activeKey={activeKey?.publicKey}
|
||||||
onSelect={selectPubKey}
|
onSelect={selectPubKey}
|
||||||
|
isReadOnly={isReadOnly}
|
||||||
/>
|
/>
|
||||||
<TradingDropdownSeparator />
|
<TradingDropdownSeparator />
|
||||||
{!isReadOnly && (
|
{!isReadOnly && (
|
||||||
@ -141,11 +142,13 @@ const KeypairRadioGroup = ({
|
|||||||
pubKeys,
|
pubKeys,
|
||||||
activeKey,
|
activeKey,
|
||||||
onSelect,
|
onSelect,
|
||||||
|
isReadOnly,
|
||||||
}: {
|
}: {
|
||||||
pubKey: string | undefined;
|
pubKey: string | undefined;
|
||||||
pubKeys: Key[];
|
pubKeys: Key[];
|
||||||
activeKey: string | undefined;
|
activeKey: string | undefined;
|
||||||
onSelect: (pubKey: string) => void;
|
onSelect: (pubKey: string) => void;
|
||||||
|
isReadOnly: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const { data } = usePartyProfilesQuery({
|
const { data } = usePartyProfilesQuery({
|
||||||
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
|
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
|
||||||
@ -165,6 +168,7 @@ const KeypairRadioGroup = ({
|
|||||||
pk={pk}
|
pk={pk}
|
||||||
isActive={activeKey === pk.publicKey}
|
isActive={activeKey === pk.publicKey}
|
||||||
alias={profile?.node.alias}
|
alias={profile?.node.alias}
|
||||||
|
isReadOnly={isReadOnly}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@ -176,10 +180,12 @@ const KeypairItem = ({
|
|||||||
pk,
|
pk,
|
||||||
isActive,
|
isActive,
|
||||||
alias,
|
alias,
|
||||||
|
isReadOnly,
|
||||||
}: {
|
}: {
|
||||||
pk: Key;
|
pk: Key;
|
||||||
alias: string | undefined;
|
alias: string | undefined;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
isReadOnly: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const [copied, setCopied] = useCopyTimeout();
|
const [copied, setCopied] = useCopyTimeout();
|
||||||
@ -210,16 +216,18 @@ const KeypairItem = ({
|
|||||||
className={classNames('flex-1 mr-2 text-secondary text-sm')}
|
className={classNames('flex-1 mr-2 text-secondary text-sm')}
|
||||||
data-testid={`key-${pk.publicKey}`}
|
data-testid={`key-${pk.publicKey}`}
|
||||||
>
|
>
|
||||||
<Tooltip description={t('Public facing key alias. Click to edit')}>
|
{!isReadOnly && (
|
||||||
<button
|
<Tooltip description={t('Public facing key alias. Click to edit')}>
|
||||||
data-testid="alias"
|
<button
|
||||||
onClick={() => setOpen(pk.publicKey)}
|
data-testid="alias"
|
||||||
className="flex items-center gap-1"
|
onClick={() => setOpen(pk.publicKey)}
|
||||||
>
|
className="flex items-center gap-1"
|
||||||
{alias ? alias : t('No alias')}
|
>
|
||||||
{isActive && <VegaIcon name={VegaIconNames.EDIT} />}
|
{alias ? alias : t('No alias')}
|
||||||
</button>
|
{isActive && <VegaIcon name={VegaIconNames.EDIT} />}
|
||||||
</Tooltip>
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<TradingDropdownItemIndicator />
|
<TradingDropdownItemIndicator />
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest
|
CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest
|
||||||
VEGA_VERSION=v0.75.0-preview.2
|
VEGA_VERSION=v0.75.5
|
||||||
LOCAL_SERVER=false
|
LOCAL_SERVER=false
|
||||||
|
VEGA_ENV=STAGNET1
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:develop
|
CONSOLE_IMAGE_NAME=vegaprotocol/trading:develop
|
||||||
VEGA_VERSION=v0.74.6
|
VEGA_VERSION=v0.75.5
|
||||||
LOCAL_SERVER=false
|
LOCAL_SERVER=false
|
||||||
|
VEGA_ENV=STAGNET1
|
@ -1,3 +1,4 @@
|
|||||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:main
|
CONSOLE_IMAGE_NAME=vegaprotocol/trading:main
|
||||||
VEGA_VERSION=v0.73.13
|
VEGA_VERSION=v0.74.10
|
||||||
LOCAL_SERVER=false
|
LOCAL_SERVER=false
|
||||||
|
VEGA_ENV=MAINNET
|
@ -92,7 +92,7 @@ def init_vega(request=None):
|
|||||||
"store_transactions": True,
|
"store_transactions": True,
|
||||||
"transactions_per_block": 1000,
|
"transactions_per_block": 1000,
|
||||||
"seconds_per_block": seconds_per_block,
|
"seconds_per_block": seconds_per_block,
|
||||||
"genesis_time": datetime.now() - timedelta(days=1),
|
"genesis_time": datetime.now() - timedelta(hours=1),
|
||||||
}
|
}
|
||||||
|
|
||||||
if port_config is not None:
|
if port_config is not None:
|
||||||
@ -153,10 +153,13 @@ def init_page(vega: VegaServiceNull, browser: Browser, request: pytest.FixtureRe
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
# Set window._env_ so built app uses datanode from vega market sim
|
# Set window._env_ so built app uses datanode from vega market sim
|
||||||
|
load_dotenv()
|
||||||
|
vega_env = os.getenv('VEGA_ENV')
|
||||||
env = json.dumps(
|
env = json.dumps(
|
||||||
{
|
{
|
||||||
"VEGA_URL": f"http://localhost:{vega.data_node_rest_port}/graphql",
|
"VEGA_URL": f"http://localhost:{vega.data_node_rest_port}/graphql",
|
||||||
"VEGA_WALLET_URL": f"http://localhost:{vega.wallet_port}",
|
"VEGA_WALLET_URL": f"http://localhost:{vega.wallet_port}",
|
||||||
|
"VEGA_ENV": vega_env,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
window_env = f"window._env_ = Object.assign({{}}, window._env_, {env})"
|
window_env = f"window._env_ = Object.assign({{}}, window._env_, {env})"
|
||||||
|
286
apps/trading/e2e/poetry.lock
generated
286
apps/trading/e2e/poetry.lock
generated
@ -1,4 +1,4 @@
|
|||||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
@ -253,13 +253,13 @@ testing = ["hatch", "pre-commit", "pytest", "tox"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "googleapis-common-protos"
|
name = "googleapis-common-protos"
|
||||||
version = "1.62.0"
|
version = "1.63.0"
|
||||||
description = "Common protobufs used in Google APIs"
|
description = "Common protobufs used in Google APIs"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"},
|
{file = "googleapis-common-protos-1.63.0.tar.gz", hash = "sha256:17ad01b11d5f1d0171c06d3ba5c04c54474e883b66b949722b4938ee2694ef4e"},
|
||||||
{file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"},
|
{file = "googleapis_common_protos-1.63.0-py2.py3-none-any.whl", hash = "sha256:ae45f75702f7c08b541f750854a678bd8f534a1a6bace6afe975f1d0a82d6632"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -341,135 +341,135 @@ test = ["objgraph", "psutil"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grpcio"
|
name = "grpcio"
|
||||||
version = "1.62.0"
|
version = "1.62.1"
|
||||||
description = "HTTP/2-based RPC framework"
|
description = "HTTP/2-based RPC framework"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "grpcio-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271"},
|
{file = "grpcio-1.62.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:179bee6f5ed7b5f618844f760b6acf7e910988de77a4f75b95bbfaa8106f3c1e"},
|
||||||
{file = "grpcio-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0"},
|
{file = "grpcio-1.62.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:48611e4fa010e823ba2de8fd3f77c1322dd60cb0d180dc6630a7e157b205f7ea"},
|
||||||
{file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6"},
|
{file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:b2a0e71b0a2158aa4bce48be9f8f9eb45cbd17c78c7443616d00abbe2a509f6d"},
|
||||||
{file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8"},
|
{file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbe80577c7880911d3ad65e5ecc997416c98f354efeba2f8d0f9112a67ed65a5"},
|
||||||
{file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c"},
|
{file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58f6c693d446964e3292425e1d16e21a97a48ba9172f2d0df9d7b640acb99243"},
|
||||||
{file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0"},
|
{file = "grpcio-1.62.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:77c339403db5a20ef4fed02e4d1a9a3d9866bf9c0afc77a42234677313ea22f3"},
|
||||||
{file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6"},
|
{file = "grpcio-1.62.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b5a4ea906db7dec694098435d84bf2854fe158eb3cd51e1107e571246d4d1d70"},
|
||||||
{file = "grpcio-1.62.0-cp310-cp310-win32.whl", hash = "sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc"},
|
{file = "grpcio-1.62.1-cp310-cp310-win32.whl", hash = "sha256:4187201a53f8561c015bc745b81a1b2d278967b8de35f3399b84b0695e281d5f"},
|
||||||
{file = "grpcio-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa"},
|
{file = "grpcio-1.62.1-cp310-cp310-win_amd64.whl", hash = "sha256:844d1f3fb11bd1ed362d3fdc495d0770cfab75761836193af166fee113421d66"},
|
||||||
{file = "grpcio-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f"},
|
{file = "grpcio-1.62.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:833379943d1728a005e44103f17ecd73d058d37d95783eb8f0b28ddc1f54d7b2"},
|
||||||
{file = "grpcio-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb"},
|
{file = "grpcio-1.62.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:c7fcc6a32e7b7b58f5a7d27530669337a5d587d4066060bcb9dee7a8c833dfb7"},
|
||||||
{file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928"},
|
{file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:fa7d28eb4d50b7cbe75bb8b45ed0da9a1dc5b219a0af59449676a29c2eed9698"},
|
||||||
{file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2"},
|
{file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48f7135c3de2f298b833be8b4ae20cafe37091634e91f61f5a7eb3d61ec6f660"},
|
||||||
{file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021"},
|
{file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71f11fd63365ade276c9d4a7b7df5c136f9030e3457107e1791b3737a9b9ed6a"},
|
||||||
{file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4"},
|
{file = "grpcio-1.62.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4b49fd8fe9f9ac23b78437da94c54aa7e9996fbb220bac024a67469ce5d0825f"},
|
||||||
{file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e"},
|
{file = "grpcio-1.62.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:482ae2ae78679ba9ed5752099b32e5fe580443b4f798e1b71df412abf43375db"},
|
||||||
{file = "grpcio-1.62.0-cp311-cp311-win32.whl", hash = "sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd"},
|
{file = "grpcio-1.62.1-cp311-cp311-win32.whl", hash = "sha256:1faa02530b6c7426404372515fe5ddf66e199c2ee613f88f025c6f3bd816450c"},
|
||||||
{file = "grpcio-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334"},
|
{file = "grpcio-1.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bd90b8c395f39bc82a5fb32a0173e220e3f401ff697840f4003e15b96d1befc"},
|
||||||
{file = "grpcio-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8"},
|
{file = "grpcio-1.62.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:b134d5d71b4e0837fff574c00e49176051a1c532d26c052a1e43231f252d813b"},
|
||||||
{file = "grpcio-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6"},
|
{file = "grpcio-1.62.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:d1f6c96573dc09d50dbcbd91dbf71d5cf97640c9427c32584010fbbd4c0e0037"},
|
||||||
{file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532"},
|
{file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:359f821d4578f80f41909b9ee9b76fb249a21035a061a327f91c953493782c31"},
|
||||||
{file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee"},
|
{file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a485f0c2010c696be269184bdb5ae72781344cb4e60db976c59d84dd6354fac9"},
|
||||||
{file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c"},
|
{file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b50b09b4dc01767163d67e1532f948264167cd27f49e9377e3556c3cba1268e1"},
|
||||||
{file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873"},
|
{file = "grpcio-1.62.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3227c667dccbe38f2c4d943238b887bac588d97c104815aecc62d2fd976e014b"},
|
||||||
{file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388"},
|
{file = "grpcio-1.62.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3952b581eb121324853ce2b191dae08badb75cd493cb4e0243368aa9e61cfd41"},
|
||||||
{file = "grpcio-1.62.0-cp312-cp312-win32.whl", hash = "sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701"},
|
{file = "grpcio-1.62.1-cp312-cp312-win32.whl", hash = "sha256:83a17b303425104d6329c10eb34bba186ffa67161e63fa6cdae7776ff76df73f"},
|
||||||
{file = "grpcio-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842"},
|
{file = "grpcio-1.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:6696ffe440333a19d8d128e88d440f91fb92c75a80ce4b44d55800e656a3ef1d"},
|
||||||
{file = "grpcio-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9"},
|
{file = "grpcio-1.62.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:e3393b0823f938253370ebef033c9fd23d27f3eae8eb9a8f6264900c7ea3fb5a"},
|
||||||
{file = "grpcio-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2"},
|
{file = "grpcio-1.62.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:83e7ccb85a74beaeae2634f10eb858a0ed1a63081172649ff4261f929bacfd22"},
|
||||||
{file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1"},
|
{file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:882020c87999d54667a284c7ddf065b359bd00251fcd70279ac486776dbf84ec"},
|
||||||
{file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839"},
|
{file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a10383035e864f386fe096fed5c47d27a2bf7173c56a6e26cffaaa5a361addb1"},
|
||||||
{file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4"},
|
{file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:960edebedc6b9ada1ef58e1c71156f28689978188cd8cff3b646b57288a927d9"},
|
||||||
{file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b"},
|
{file = "grpcio-1.62.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:23e2e04b83f347d0aadde0c9b616f4726c3d76db04b438fd3904b289a725267f"},
|
||||||
{file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b"},
|
{file = "grpcio-1.62.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:978121758711916d34fe57c1f75b79cdfc73952f1481bb9583399331682d36f7"},
|
||||||
{file = "grpcio-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b"},
|
{file = "grpcio-1.62.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9084086190cc6d628f282e5615f987288b95457292e969b9205e45b442276407"},
|
||||||
{file = "grpcio-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35"},
|
{file = "grpcio-1.62.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:22bccdd7b23c420a27fd28540fb5dcbc97dc6be105f7698cb0e7d7a420d0e362"},
|
||||||
{file = "grpcio-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6"},
|
{file = "grpcio-1.62.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:8999bf1b57172dbc7c3e4bb3c732658e918f5c333b2942243f10d0d653953ba9"},
|
||||||
{file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c"},
|
{file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:d9e52558b8b8c2f4ac05ac86344a7417ccdd2b460a59616de49eb6933b07a0bd"},
|
||||||
{file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402"},
|
{file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1714e7bc935780bc3de1b3fcbc7674209adf5208ff825799d579ffd6cd0bd505"},
|
||||||
{file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72"},
|
{file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8842ccbd8c0e253c1f189088228f9b433f7a93b7196b9e5b6f87dba393f5d5d"},
|
||||||
{file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f"},
|
{file = "grpcio-1.62.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1f1e7b36bdff50103af95a80923bf1853f6823dd62f2d2a2524b66ed74103e49"},
|
||||||
{file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38"},
|
{file = "grpcio-1.62.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bba97b8e8883a8038606480d6b6772289f4c907f6ba780fa1f7b7da7dfd76f06"},
|
||||||
{file = "grpcio-1.62.0-cp38-cp38-win32.whl", hash = "sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe"},
|
{file = "grpcio-1.62.1-cp38-cp38-win32.whl", hash = "sha256:a7f615270fe534548112a74e790cd9d4f5509d744dd718cd442bf016626c22e4"},
|
||||||
{file = "grpcio-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270"},
|
{file = "grpcio-1.62.1-cp38-cp38-win_amd64.whl", hash = "sha256:e6c8c8693df718c5ecbc7babb12c69a4e3677fd11de8886f05ab22d4e6b1c43b"},
|
||||||
{file = "grpcio-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170"},
|
{file = "grpcio-1.62.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:73db2dc1b201d20ab7083e7041946910bb991e7e9761a0394bbc3c2632326483"},
|
||||||
{file = "grpcio-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e"},
|
{file = "grpcio-1.62.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:407b26b7f7bbd4f4751dbc9767a1f0716f9fe72d3d7e96bb3ccfc4aace07c8de"},
|
||||||
{file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829"},
|
{file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:f8de7c8cef9261a2d0a62edf2ccea3d741a523c6b8a6477a340a1f2e417658de"},
|
||||||
{file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b"},
|
{file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd5c8a1af40ec305d001c60236308a67e25419003e9bb3ebfab5695a8d0b369"},
|
||||||
{file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7"},
|
{file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be0477cb31da67846a33b1a75c611f88bfbcd427fe17701b6317aefceee1b96f"},
|
||||||
{file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c"},
|
{file = "grpcio-1.62.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:60dcd824df166ba266ee0cfaf35a31406cd16ef602b49f5d4dfb21f014b0dedd"},
|
||||||
{file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a"},
|
{file = "grpcio-1.62.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:973c49086cabab773525f6077f95e5a993bfc03ba8fc32e32f2c279497780585"},
|
||||||
{file = "grpcio-1.62.0-cp39-cp39-win32.whl", hash = "sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93"},
|
{file = "grpcio-1.62.1-cp39-cp39-win32.whl", hash = "sha256:12859468e8918d3bd243d213cd6fd6ab07208195dc140763c00dfe901ce1e1b4"},
|
||||||
{file = "grpcio-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5"},
|
{file = "grpcio-1.62.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7209117bbeebdfa5d898205cc55153a51285757902dd73c47de498ad4d11332"},
|
||||||
{file = "grpcio-1.62.0.tar.gz", hash = "sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7"},
|
{file = "grpcio-1.62.1.tar.gz", hash = "sha256:6c455e008fa86d9e9a9d85bb76da4277c0d7d9668a3bfa70dbe86e9f3c759947"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
protobuf = ["grpcio-tools (>=1.62.0)"]
|
protobuf = ["grpcio-tools (>=1.62.1)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grpcio-tools"
|
name = "grpcio-tools"
|
||||||
version = "1.62.0"
|
version = "1.62.1"
|
||||||
description = "Protobuf code generator for gRPC"
|
description = "Protobuf code generator for gRPC"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "grpcio-tools-1.62.0.tar.gz", hash = "sha256:7fca6ecfbbf0549058bb29dcc6e435d885b878d07701e77ac58e1e1f591736dc"},
|
{file = "grpcio-tools-1.62.1.tar.gz", hash = "sha256:a4991e5ee8a97ab791296d3bf7e8700b1445635cc1828cc98df945ca1802d7f2"},
|
||||||
{file = "grpcio_tools-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:465c51ebaa184ee3bb619cd5bfaf562bbdde166f2822a6935461e6a741f5ac19"},
|
{file = "grpcio_tools-1.62.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:f2b404bcae7e2ef9b0b9803b2a95119eb7507e6dc80ea4a64a78be052c30cebc"},
|
||||||
{file = "grpcio_tools-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:0d9c9a4832f52c4597d6dc12d9ab3109c3bd0ee1686b8bf6d64f9eab4145e3cb"},
|
{file = "grpcio_tools-1.62.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:fdd987a580b4474769adfd40144486f54bcc73838d5ec5d3647a17883ea78e76"},
|
||||||
{file = "grpcio_tools-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:5a482d9625209023481e631c29a6df1392bfc49f9accfa880dabbacff642559a"},
|
{file = "grpcio_tools-1.62.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:07af1a6442e2313cff22af93c2c4dd37ae32b5239b38e0d99e2cbf93de65429f"},
|
||||||
{file = "grpcio_tools-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74196beed18383d53ff3e2412a6c1eefa3ff109e987be240368496bc3dcabc8b"},
|
{file = "grpcio_tools-1.62.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41384c9ee18e61ef20cad2774ef71bd8854b63efce263b5177aa06fccb84df1f"},
|
||||||
{file = "grpcio_tools-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aca28cbeb605c59b5689a7e000fbc2bd659d2f322c58461f3912f00069f6da"},
|
{file = "grpcio_tools-1.62.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c38006f7702d2ff52122e4c77a47348709374050c76216e84b30a9f06e45afa"},
|
||||||
{file = "grpcio_tools-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:523adf731fa4c5af0bf7ee2edb65e8c7ef4d9df9951461d6a18fe096688efd2d"},
|
{file = "grpcio_tools-1.62.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:08fecc3c5b4e6dd3278f2b9d12837e423c7dcff551ca1e587018b4a0fc5f8019"},
|
||||||
{file = "grpcio_tools-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:791aa220f8f1936e65bc079e9eb954fa0202a1f16e28b83956e59d17dface127"},
|
{file = "grpcio_tools-1.62.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a01e8dcd0f041f6fa6d815c54a2017d032950e310c41d514a8bc041e872c4d12"},
|
||||||
{file = "grpcio_tools-1.62.0-cp310-cp310-win32.whl", hash = "sha256:5dacc691b18d2c294ea971720ff980a1e2d68a3f7ddcd2f0670b3204e81c4b18"},
|
{file = "grpcio_tools-1.62.1-cp310-cp310-win32.whl", hash = "sha256:dd933b8e0b3c13fe3543d58f849a6a5e0d7987688cb6801834278378c724f695"},
|
||||||
{file = "grpcio_tools-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:6999a4e705b03aacad46e625feb7610e47ec88dbd51220c2282b6334f90721fc"},
|
{file = "grpcio_tools-1.62.1-cp310-cp310-win_amd64.whl", hash = "sha256:2b04844a9382f1bde4b4174e476e654ab3976168d2469cb4b29e352f4f35a5aa"},
|
||||||
{file = "grpcio_tools-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:19b74e141937c885c9e56b6a7dfa190ca7d583bd48bce9171dd65bbf108b9271"},
|
{file = "grpcio_tools-1.62.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:024380536ba71a96cdf736f0954f6ad03f5da609c09edbcc2ca02fdd639e0eed"},
|
||||||
{file = "grpcio_tools-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:17c16e9a89c0b9f4ff2b143f232c5256383453ce7b55fe981598f9517adc8252"},
|
{file = "grpcio_tools-1.62.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:21f14b99e0cd38ad56754cc0b62b2bf3cf75f9f7fc40647da54669e0da0726fe"},
|
||||||
{file = "grpcio_tools-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:3730b1cd998a0cffc817602cc55e51f268fa97b3e38fa4bee578e3741474547a"},
|
{file = "grpcio_tools-1.62.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:975ac5fb482c23f3608c16e06a43c8bab4d79c2e2564cdbc25cf753c6e998775"},
|
||||||
{file = "grpcio_tools-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14201950513636f515dd455a06890e3a21d115b943cf6a8f5af67ad1413cfa1f"},
|
{file = "grpcio_tools-1.62.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50739aaab0c8076ad5957204e71f2e0c9876e11fd8338f7f09de12c2d75163c5"},
|
||||||
{file = "grpcio_tools-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f74e0053360e0eadd75193c0c379b6d7f51d074ebbff856bd41780e1a028b38d"},
|
{file = "grpcio_tools-1.62.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598c54318f0326cf5020aa43fc95a15e933aba4a71943d3bff2677d2d21ddfa1"},
|
||||||
{file = "grpcio_tools-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d5959e3df126931d28cd94dd5f0a708b7dd96019de80ab715fb922fd0c8a838d"},
|
{file = "grpcio_tools-1.62.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f309bdb33a61f8e049480d41498ee2e525cfb5e959958b326abfdf552bf9b9cb"},
|
||||||
{file = "grpcio_tools-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1927934dfba4658a97c2dab267e53ed239264d40fdd5b295fc317693543db85b"},
|
{file = "grpcio_tools-1.62.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f358effd3c11d66c150e0227f983d54a5cd30e14038566dadcf25f9f6844e6e8"},
|
||||||
{file = "grpcio_tools-1.62.0-cp311-cp311-win32.whl", hash = "sha256:2f5bd22203e64e1732e149bfdd3083716d038abca294e4e2852159b3d893f9ec"},
|
{file = "grpcio_tools-1.62.1-cp311-cp311-win32.whl", hash = "sha256:b76aead9b73f1650a091870fe4e9ed15ac4d8ed136f962042367255199c23594"},
|
||||||
{file = "grpcio_tools-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:cd1f4caeca614b04db803566473f7db0971e7a88268f95e4a529b0ace699b949"},
|
{file = "grpcio_tools-1.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:d66a5d47eaa427039752fa0a83a425ff2a487b6a0ac30556fd3be2f3a27a0130"},
|
||||||
{file = "grpcio_tools-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:f0884eaf6a2bbd7b03fea456e808909ee48dd4f7f455519d67defda791116368"},
|
{file = "grpcio_tools-1.62.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:575535d039b97d63e6a9abee626d6c7cd47bd8cb73dd00a5c84a98254a2164a4"},
|
||||||
{file = "grpcio_tools-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:6b900ae319b6f9ac1be0ca572dfb41c23a7ff6fcbf36e3be6d3054e1e4c60de6"},
|
{file = "grpcio_tools-1.62.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:22644c90e43d1a888477899af917979e17364fdd6e9bbb92679cd6a54c4d36c3"},
|
||||||
{file = "grpcio_tools-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:3bbe79b134dfb7c98cf60e4962e31039bef824834cc7034bdf1886a2ed1097f9"},
|
{file = "grpcio_tools-1.62.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:156d3e1b227c16e903003a56881dbe60e40f2b4bd66f0bc3b27c53e466e6384d"},
|
||||||
{file = "grpcio_tools-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77196c7ac8741d4a2aebb023bcc2964ac65ca44180fd791640889ab2afed3e47"},
|
{file = "grpcio_tools-1.62.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ad7c5691625a85327e5b683443baf73ae790fd5afc938252041ed5cd665e377"},
|
||||||
{file = "grpcio_tools-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b65288ebe12e38dd3650fea65d82fcce0d35df1ae4a770b525c10119ee71962f"},
|
{file = "grpcio_tools-1.62.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e140bbc08eea8abf51c0274f45fb1e8350220e64758998d7f3c7f985a0b2496"},
|
||||||
{file = "grpcio_tools-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:52b216c458458f6c292e12428916e80974c5113abc505a61e7b0b9f8932a785d"},
|
{file = "grpcio_tools-1.62.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7444fcab861911525470d398e5638b70d5cbea3b4674a3de92b5c58c5c515d4d"},
|
||||||
{file = "grpcio_tools-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88aa62303278aec45bbb26bf679269c7890346c37140ae30e39da1070c341e11"},
|
{file = "grpcio_tools-1.62.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e643cd14a5d1e59865cba68a5a6f0175d987f36c5f4cb0db80dee9ed60b4c174"},
|
||||||
{file = "grpcio_tools-1.62.0-cp312-cp312-win32.whl", hash = "sha256:bb6802d63e42734d2baf02e1343377fe18590ed6a1f5ffbdebbbe0f8331f176b"},
|
{file = "grpcio_tools-1.62.1-cp312-cp312-win32.whl", hash = "sha256:1344a773d2caa9bb7fbea7e879b84f33740c808c34a5bd2a2768e526117a6b44"},
|
||||||
{file = "grpcio_tools-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:d5652d3a52a2e8e1d9bdf28fbd15e21b166e31b968cd7c8c604bf31611c0bb5b"},
|
{file = "grpcio_tools-1.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:2eea1db3748b2f37b4dce84d8e0c15d9bc811094807cabafe7b0ea47f424dfd5"},
|
||||||
{file = "grpcio_tools-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:84e27206bd884be83a7fdcef8be3c90eb1591341c0ba9b0d25ec9db1043ba2f2"},
|
{file = "grpcio_tools-1.62.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:45d2e6cf04d27286b6f73e6e20ba3f0a1f6d8f5535e5dcb1356200419bb457f4"},
|
||||||
{file = "grpcio_tools-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:5eb63d9207b02a0fa30216907e1e7705cc2670f933e77236c6e0eb966ad3b4bf"},
|
{file = "grpcio_tools-1.62.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:46ae58e6926773e7315e9005f0f17aacedbc0895a8752bec087d24efa2f1fb21"},
|
||||||
{file = "grpcio_tools-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:95e49839d49e79187c43cd63af5c206dc5743a01d7d3d2f039772fa743cbb30c"},
|
{file = "grpcio_tools-1.62.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:4c28086df31478023a36f45e50767872ab3aed2419afff09814cb61c88b77db4"},
|
||||||
{file = "grpcio_tools-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ae5cd2f89e33a529790bf8aa59a459484edb05e4f58d4cf78836b9dfa1fab43"},
|
{file = "grpcio_tools-1.62.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4fba5b339f4797548591036c9481e6895bf920fab7d3dc664d2697f8fb7c0bf"},
|
||||||
{file = "grpcio_tools-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e1fd7301d762bf5984b7e7fb62fce82cff864d75f0a57e15cfd07ae1bd79133"},
|
{file = "grpcio_tools-1.62.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23eb3d47f78f509fcd201749b1f1e44b76f447913f7fbb3b8bae20f109086295"},
|
||||||
{file = "grpcio_tools-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e38d5800151e6804d500e329f7ddfb615c50eee0c1607593e3147a4b21037e40"},
|
{file = "grpcio_tools-1.62.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fd5d47707bd6bc2b707ece765c362d2a1d2e8f6cd92b04c99fab49a929f3610c"},
|
||||||
{file = "grpcio_tools-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:563a75924109e75809b2919e68d7e6ae7872e63d20258aae7899b14f6ff9e18b"},
|
{file = "grpcio_tools-1.62.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d1924a6a943df7c73b9ef0048302327c75962b567451479710da729ead241228"},
|
||||||
{file = "grpcio_tools-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5f8934715577c9cc0c792b8a77f7d0dd2bb60e951161b10c5f46b60856673240"},
|
{file = "grpcio_tools-1.62.1-cp37-cp37m-win_amd64.whl", hash = "sha256:fe71ca30aabe42591e84ecb9694c0297dc699cc20c5b24d2cb267fb0fc01f947"},
|
||||||
{file = "grpcio_tools-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:ed6cf7ff4a10c46f85340f9c68982f9efb29f51ee4b66828310fcdf3c2d7ffd1"},
|
{file = "grpcio_tools-1.62.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:1819fd055c1ae672d1d725ec75eefd1f700c18acba0ed9332202be31d69c401d"},
|
||||||
{file = "grpcio_tools-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:1faa5006fe9e7b9e65c47bc23f7cd333fdcdd4ba35d44080303848266db5ab05"},
|
{file = "grpcio_tools-1.62.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:5dbe1f7481dd14b6d477b4bace96d275090bc7636b9883975a08b802c94e7b78"},
|
||||||
{file = "grpcio_tools-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:3b526dc5566161a3a17599753838b9cfbdd4cb15b6ad419aae8a5d12053fa8ae"},
|
{file = "grpcio_tools-1.62.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:771c051c5ece27ad03e4f2e33624a925f0ad636c01757ab7dbb04a37964af4ba"},
|
||||||
{file = "grpcio_tools-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09db3688efd3499ce3c0b02c0bac0656abdab4cb99716f81ad879c08b92c56e"},
|
{file = "grpcio_tools-1.62.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:98209c438b38b6f1276dbc27b1c04e346a75bfaafe72a25a548f2dc5ce71d226"},
|
||||||
{file = "grpcio_tools-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:006ea0cc16e8bf8f307326e0556e1384f24abb402cc4e6a720aa1dfe8f268647"},
|
{file = "grpcio_tools-1.62.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2152308e5321cb90fb45aaa84d03d6dedb19735a8779aaf36c624f97b831842d"},
|
||||||
{file = "grpcio_tools-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b46ba0b6552b4375ede65e0c89491af532635347f78d52a72f8a027529e713ed"},
|
{file = "grpcio_tools-1.62.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ed1f27dc2b2262c8b8d9036276619c1bb18791311c16ccbf1f31b660f2aad7cf"},
|
||||||
{file = "grpcio_tools-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ec6f561c86fe13cff3be16f297cc05e1aa1274294524743a4cf91d971866fbb0"},
|
{file = "grpcio_tools-1.62.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2744947b6c5e907af21133431809ccca535a037356864e32c122efed8cb9de1f"},
|
||||||
{file = "grpcio_tools-1.62.0-cp38-cp38-win32.whl", hash = "sha256:c85391e06620d6e16a56341caae5007d0c6219beba065e1e288f2523fba6a335"},
|
{file = "grpcio_tools-1.62.1-cp38-cp38-win32.whl", hash = "sha256:13b20e269d14ad629ff9a2c9a2450f3dbb119d5948de63b27ffe624fa7aea85a"},
|
||||||
{file = "grpcio_tools-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:679cf2507090e010da73e5001665c76de2a5927b2e2110e459222b1c81cb10c2"},
|
{file = "grpcio_tools-1.62.1-cp38-cp38-win_amd64.whl", hash = "sha256:999823758e9eacd0095863d06cd6d388be769f80c9abb65cdb11c4f2cfce3fea"},
|
||||||
{file = "grpcio_tools-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:0e87f105f1d152934759f8975ed002d5ce057b3cdf1cc6cb63fe6008671a27b9"},
|
{file = "grpcio_tools-1.62.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:941f8a5c31986053e75fa466bcfa743c2bf1b513b7978cf1f4ab4e96a8219d27"},
|
||||||
{file = "grpcio_tools-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:bf9f281f528e0220558d57e09b4518dec148dcb250d78bd9cbb27e09edabb3f9"},
|
{file = "grpcio_tools-1.62.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:b9c02c88c77ef6057c6cbeea8922d7c2424aabf46bfc40ddf42a32765ba91061"},
|
||||||
{file = "grpcio_tools-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:711314cb4c6c8b3d51bafaee380ffa5012bd0567ed68f1b0b1fc07492b27acab"},
|
{file = "grpcio_tools-1.62.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:6abd4eb3ccb444383a40156139acc3aaa73745d395139cb6bc8e2a3429e1e627"},
|
||||||
{file = "grpcio_tools-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54bb570bd963905de3bda596b35e06026552705edebbb2cb737b57aa5252b9e5"},
|
{file = "grpcio_tools-1.62.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:449503213d142f8470b331a1c2f346f8457f16c7fe20f531bc2500e271f7c14c"},
|
||||||
{file = "grpcio_tools-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dce5f04676cf94e6e2d13d7f91ac2de79097d86675bc4d404a3c24dcc0332c88"},
|
{file = "grpcio_tools-1.62.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a11bcf609d00cfc9baed77ab308223cabc1f0b22a05774a26dd4c94c0c80f1f"},
|
||||||
{file = "grpcio_tools-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:98ddf871c614cc0ed331c7159ebbbf5040be562279677d3bb97c2e6083539f72"},
|
{file = "grpcio_tools-1.62.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5d7bdea33354b55acf40bb4dd3ba7324d6f1ef6b4a1a4da0807591f8c7e87b9a"},
|
||||||
{file = "grpcio_tools-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f3aaf3b20c0f7063856b2432335af8f76cf580f898e04085548cde28332d6833"},
|
{file = "grpcio_tools-1.62.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d03b645852d605f43003020e78fe6d573cae6ee6b944193e36b8b317e7549a20"},
|
||||||
{file = "grpcio_tools-1.62.0-cp39-cp39-win32.whl", hash = "sha256:3dee3be61d9032f777a9b4e2696ea3d0748a582cb99c672b5d41ca66821e8c87"},
|
{file = "grpcio_tools-1.62.1-cp39-cp39-win32.whl", hash = "sha256:52b185dfc3bf32e70929310367dbc66185afba60492a6a75a9b1141d407e160c"},
|
||||||
{file = "grpcio_tools-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:f54b5181784464bd3573ae7dbcf053da18a4b7a75fe19960791f383be3d035ca"},
|
{file = "grpcio_tools-1.62.1-cp39-cp39-win_amd64.whl", hash = "sha256:63a273b70896d3640b7a883eb4a080c3c263d91662d870a2e9c84b7bbd978e7b"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
grpcio = ">=1.62.0"
|
grpcio = ">=1.62.1"
|
||||||
protobuf = ">=4.21.6,<5.0dev"
|
protobuf = ">=4.21.6,<5.0dev"
|
||||||
setuptools = "*"
|
setuptools = "*"
|
||||||
|
|
||||||
@ -553,13 +553,13 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "packaging"
|
name = "packaging"
|
||||||
version = "23.2"
|
version = "24.0"
|
||||||
description = "Core utilities for Python packages"
|
description = "Core utilities for Python packages"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
|
{file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"},
|
||||||
{file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
|
{file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -633,18 +633,18 @@ xml = ["lxml (>=4.9.2)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "playwright"
|
name = "playwright"
|
||||||
version = "1.41.2"
|
version = "1.42.0"
|
||||||
description = "A high-level API to automate web browsers"
|
description = "A high-level API to automate web browsers"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "playwright-1.41.2-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:cf68335a5dfa4038fa797a4ba0105faee0094ebbb372547d7a27feec5b23c672"},
|
{file = "playwright-1.42.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:e2b293f077efeaa45253fde31cea4bc6b0ae8be6b5e65e8ce8b4aa3b9f0d55b6"},
|
||||||
{file = "playwright-1.41.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:431e3a05f8c99147995e2b3e8475d07818745294fd99f1510b61756e73bdcf68"},
|
{file = "playwright-1.42.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:283887f0bdd0039c3d720e32fbc73a045c24fa800599a6ad60fb199c29580534"},
|
||||||
{file = "playwright-1.41.2-py3-none-macosx_11_0_universal2.whl", hash = "sha256:0608717cbf291a625ba6f751061af0fc0cc9bdace217e69d87b1eb1383b03406"},
|
{file = "playwright-1.42.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:4e1fc1c049a0af64626ddd50814d14a01f316bcbb4d1aa83c3416fe420add558"},
|
||||||
{file = "playwright-1.41.2-py3-none-manylinux1_x86_64.whl", hash = "sha256:4bf214d812092cf5b9b9648ba84611aa35e28685519911342a7da3a3031f9ed6"},
|
{file = "playwright-1.42.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:313f2551a772f57c9ccca017c4dd4661f2277166f9e1d84bbf5a2e316f0f892c"},
|
||||||
{file = "playwright-1.41.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eaa17ab44622c447de26ed8f7d99912719568d8dbc3a9db0e07f0ae1487709d9"},
|
{file = "playwright-1.42.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2a46a24641e5d468046cde567c98fdb8d85e32df901630b14dfb288cbd1ed4f"},
|
||||||
{file = "playwright-1.41.2-py3-none-win32.whl", hash = "sha256:edb210a015e70bb0d328bf1c9b65fa3a08361f33e4d7c4ddd1ad2adb6d9b4479"},
|
{file = "playwright-1.42.0-py3-none-win32.whl", hash = "sha256:dbf473496808d4c2c816902c1dee2aabc029648e56ce8514b643f5a1a6fc8e22"},
|
||||||
{file = "playwright-1.41.2-py3-none-win_amd64.whl", hash = "sha256:71ead0f33e00f5a8533c037c647938b99f219436a1b27d4ba4de4e6bf0567278"},
|
{file = "playwright-1.42.0-py3-none-win_amd64.whl", hash = "sha256:e092c6cfbf797bff03fbdfc53c3e6a9e29fbcf6b82f9e43113d37494aee0561b"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -653,13 +653,13 @@ pyee = "11.0.1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "plotly"
|
name = "plotly"
|
||||||
version = "5.19.0"
|
version = "5.20.0"
|
||||||
description = "An open-source, interactive data visualization library for Python"
|
description = "An open-source, interactive data visualization library for Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "plotly-5.19.0-py3-none-any.whl", hash = "sha256:906abcc5f15945765328c5d47edaa884bc99f5985fbc61e8cd4dc361f4ff8f5a"},
|
{file = "plotly-5.20.0-py3-none-any.whl", hash = "sha256:837a9c8aa90f2c0a2f0d747b82544d014dc2a2bdde967b5bb1da25b53932d1a9"},
|
||||||
{file = "plotly-5.19.0.tar.gz", hash = "sha256:5ea91a56571292ade3e3bc9bf712eba0b95a1fb0a941375d978cc79432e055f4"},
|
{file = "plotly-5.20.0.tar.gz", hash = "sha256:bf901c805d22032cfa534b2ff7c5aa6b0659e037f19ec1e0cca7f585918b5c89"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -800,13 +800,13 @@ tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest"
|
name = "pytest"
|
||||||
version = "8.0.2"
|
version = "8.1.1"
|
||||||
description = "pytest: simple powerful testing with Python"
|
description = "pytest: simple powerful testing with Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pytest-8.0.2-py3-none-any.whl", hash = "sha256:edfaaef32ce5172d5466b5127b42e0d6d35ebbe4453f0e3505d96afd93f6b096"},
|
{file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"},
|
||||||
{file = "pytest-8.0.2.tar.gz", hash = "sha256:d4051d623a2e0b7e51960ba963193b09ce6daeb9759a451844a21e4ddedfc1bd"},
|
{file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -814,11 +814,11 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
|||||||
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
|
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
|
||||||
iniconfig = "*"
|
iniconfig = "*"
|
||||||
packaging = "*"
|
packaging = "*"
|
||||||
pluggy = ">=1.3.0,<2.0"
|
pluggy = ">=1.4,<2.0"
|
||||||
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
|
tomli = {version = ">=1", markers = "python_version < \"3.11\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest-base-url"
|
name = "pytest-base-url"
|
||||||
@ -1019,18 +1019,18 @@ test = ["asv", "gmpy2", "hypothesis", "mpmath", "pooch", "pytest", "pytest-cov",
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "setuptools"
|
name = "setuptools"
|
||||||
version = "69.1.1"
|
version = "69.2.0"
|
||||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"},
|
{file = "setuptools-69.2.0-py3-none-any.whl", hash = "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c"},
|
||||||
{file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"},
|
{file = "setuptools-69.2.0.tar.gz", hash = "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
|
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
|
||||||
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
||||||
testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
|
testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1165,8 +1165,8 @@ profile = ["pytest-profiling", "snakeviz"]
|
|||||||
[package.source]
|
[package.source]
|
||||||
type = "git"
|
type = "git"
|
||||||
url = "https://github.com/vegaprotocol/vega-market-sim.git/"
|
url = "https://github.com/vegaprotocol/vega-market-sim.git/"
|
||||||
reference = "HEAD"
|
reference = "pre-release/vega-v0.75.5"
|
||||||
resolved_reference = "53eed8942acb670783105cb1115bab76710a46dc"
|
resolved_reference = "b2a3437fc13ced2b7ecd582ca4778bbc4b0fe3a6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "websocket-client"
|
name = "websocket-client"
|
||||||
@ -1347,4 +1347,4 @@ files = [
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.9,<3.11"
|
python-versions = ">=3.9,<3.11"
|
||||||
content-hash = "39ce8400de7bf060857447281ef27bd78c9b1d9639da063b051e3ae6e7887a67"
|
content-hash = "80e87cbde486e7bb150fce0b1c974de38501bc16732952b455d43cb843426623"
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user