Compare commits
37
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab2843b796 | ||
|
|
c86fe368a2 | ||
|
|
a1cd8386da | ||
|
|
0235516e1c | ||
|
|
50706a9bab | ||
|
|
f22a3bc2d2 | ||
|
|
fde77ebccb | ||
|
|
e309669736 | ||
|
|
b1621d1191 | ||
|
|
39907f07db | ||
|
|
3dab5f3d9b | ||
|
|
3cf9ae7582 | ||
|
|
557894e2ef | ||
|
|
baf9875c69 | ||
|
|
51199b02ce | ||
|
|
bb826c88f0 | ||
|
|
0da20b750f | ||
|
|
e16c447564 | ||
|
|
a2170d27d6 | ||
|
|
00d840b7b3 | ||
|
|
2a4a05630f | ||
|
|
97f1f40f2c | ||
|
|
a8e6963521 | ||
|
|
a2bffa1dfd | ||
|
|
9253e8067a | ||
|
|
58972f0a11 | ||
|
|
a3c55fd7c3 | ||
|
|
c63cba1071 | ||
|
|
bc9d87fe30 | ||
|
|
6a21862378 | ||
|
|
0fb4348e9c | ||
|
|
b751bcf17d | ||
|
|
d32f27fcb1 | ||
|
|
d05cd6a2ed | ||
|
|
c003e5fa30 | ||
|
|
f62d3289ab | ||
|
|
a3d3d18c5c |
@@ -19,7 +19,7 @@ jobs:
|
||||
create-docker-image:
|
||||
name: Create docker image for console-test
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
#----------------------------------------------
|
||||
# check-out frontend-monorepo
|
||||
@@ -138,7 +138,7 @@ jobs:
|
||||
name: run-tests
|
||||
runs-on: 8-cores
|
||||
needs: [create-docker-image, console-test-branch]
|
||||
timeout-minutes: 20
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
#----------------------------------------------
|
||||
# load docker image
|
||||
@@ -205,7 +205,7 @@ jobs:
|
||||
# run tests
|
||||
#----------------------------------------------
|
||||
- name: Run tests
|
||||
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
|
||||
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 1 --dist loadfile --durations=45
|
||||
working-directory: apps/trading/e2e
|
||||
#----------------------------------------------
|
||||
# upload traces
|
||||
@@ -227,3 +227,46 @@ jobs:
|
||||
name: worker-logs
|
||||
path: ./logs/
|
||||
retention-days: 15
|
||||
#----------------------------------------------
|
||||
# ----- upload market-sim logs -----
|
||||
#----------------------------------------------
|
||||
- name: Prepare and Zip market-sim-logs
|
||||
if: always()
|
||||
run: |
|
||||
parent_dir="/tmp/market-sim-logs"
|
||||
echo "Creating parent directory at $parent_dir"
|
||||
mkdir -p "$parent_dir"
|
||||
|
||||
echo "Waiting for vega-sim-* folders to be created..."
|
||||
sleep 10 # Waits 10 seconds to ensure all folders are created
|
||||
|
||||
echo "Before searching for vega-sim-* folders in /tmp..."
|
||||
folders=$(find /tmp -mindepth 1 -type d -name 'vega-sim-*' -print) || echo "Find command failed with exit code $?"
|
||||
|
||||
echo "After searching for vega-sim-* folders in /tmp..."
|
||||
|
||||
if [ -z "$folders" ]; then
|
||||
echo "No vega-sim-* folders found."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Moving vega-sim-* folders to $parent_dir"
|
||||
echo "$folders" | xargs -I {} mv {} "$parent_dir/"
|
||||
|
||||
echo "Checking if $parent_dir is not empty..."
|
||||
if [ "$(ls -A $parent_dir)" ]; then
|
||||
echo "Zipping the parent directory..."
|
||||
zip -r market-sim-logs.zip "$parent_dir" && echo "Zip file created successfully."
|
||||
else
|
||||
echo "$parent_dir is empty. No zip file created."
|
||||
exit 0
|
||||
fi
|
||||
shell: /usr/bin/bash -e {0}
|
||||
|
||||
- name: Upload market-sim-logs
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: market-sim-logs
|
||||
path: market-sim-logs.zip
|
||||
retention-days: 15
|
||||
|
||||
@@ -44,7 +44,7 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
||||
cy.getByTestId('icon-cross').click();
|
||||
});
|
||||
|
||||
it.skip('Proposal page displayed on mobile', function () {
|
||||
it('Proposal page displayed on mobile', function () {
|
||||
const proposalTitle = 'Add Lorem Ipsum market';
|
||||
|
||||
cy.common_switch_to_mobile_and_click_toggle();
|
||||
@@ -55,7 +55,7 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('Able to view new asset proposal', function () {
|
||||
it.skip('Able to view new asset proposal', function () {
|
||||
const proposalTitle = 'Test new asset proposal';
|
||||
const newAssetProposalBody = getNewAssetTxBody();
|
||||
cy.VegaWalletSubmitProposal(newAssetProposalBody);
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import {
|
||||
BORDER_COLOURS,
|
||||
NestedDataList,
|
||||
sortNestedDataByChildren,
|
||||
} from './nested-data-list';
|
||||
import { NestedDataList, sortNestedDataByChildren } from './nested-data-list';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
const mockData = {
|
||||
@@ -61,38 +57,6 @@ describe('NestedDataList', () => {
|
||||
expect(parent[0].querySelector('li')).toHaveClass('pl-4 border-l-4 pt-2');
|
||||
});
|
||||
|
||||
it('should repeat the border colours in the correct order', () => {
|
||||
const colourMockData = {
|
||||
t0: {
|
||||
t1: {
|
||||
t2: {
|
||||
t3: {
|
||||
t4: {
|
||||
t5: {
|
||||
t6: {
|
||||
t7: {
|
||||
t8: {
|
||||
hello: 'world',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const tree = render(<NestedDataList data={colourMockData} />);
|
||||
const { getByTestId } = tree;
|
||||
|
||||
for (let i = 0; i < 8; i++) {
|
||||
const item = getByTestId(`T${i}`);
|
||||
const expected = BORDER_COLOURS.light[i % 5];
|
||||
expect(item.style.borderColor.toUpperCase()).toBe(expected);
|
||||
}
|
||||
});
|
||||
|
||||
it('should sort the data by values with children', () => {
|
||||
const mockData = {
|
||||
nonce: '5980890939790185837',
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type ExplorerReferralCodeOwnerQueryVariables = Types.Exact<{
|
||||
id: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type ExplorerReferralCodeOwnerQuery = { __typename?: 'Query', referralSets: { __typename?: 'ReferralSetConnection', edges: Array<{ __typename?: 'ReferralSetEdge', node: { __typename?: 'ReferralSet', createdAt: any, updatedAt: any, referrer: string } } | null> } };
|
||||
|
||||
|
||||
export const ExplorerReferralCodeOwnerDocument = gql`
|
||||
query ExplorerReferralCodeOwner($id: ID!) {
|
||||
referralSets(id: $id) {
|
||||
edges {
|
||||
node {
|
||||
createdAt
|
||||
updatedAt
|
||||
referrer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useExplorerReferralCodeOwnerQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useExplorerReferralCodeOwnerQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useExplorerReferralCodeOwnerQuery` 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 } = useExplorerReferralCodeOwnerQuery({
|
||||
* variables: {
|
||||
* id: // value for 'id'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useExplorerReferralCodeOwnerQuery(baseOptions: Apollo.QueryHookOptions<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>(ExplorerReferralCodeOwnerDocument, options);
|
||||
}
|
||||
export function useExplorerReferralCodeOwnerLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>(ExplorerReferralCodeOwnerDocument, options);
|
||||
}
|
||||
export type ExplorerReferralCodeOwnerQueryHookResult = ReturnType<typeof useExplorerReferralCodeOwnerQuery>;
|
||||
export type ExplorerReferralCodeOwnerLazyQueryHookResult = ReturnType<typeof useExplorerReferralCodeOwnerLazyQuery>;
|
||||
export type ExplorerReferralCodeOwnerQueryResult = Apollo.QueryResult<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>;
|
||||
@@ -0,0 +1,11 @@
|
||||
query ExplorerReferralCodeOwner($id: ID!) {
|
||||
referralSets(id: $id) {
|
||||
edges {
|
||||
node {
|
||||
createdAt
|
||||
updatedAt
|
||||
referrer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { ReferralCodeOwner } from './referral-code-owner';
|
||||
import type { ReferralCodeOwnerProps } from './referral-code-owner';
|
||||
import { ExplorerReferralCodeOwnerDocument } from './__generated__/code-owner';
|
||||
const renderComponent = (
|
||||
props: ReferralCodeOwnerProps,
|
||||
mocks: MockedResponse[]
|
||||
) => {
|
||||
return render(
|
||||
<MockedProvider mocks={mocks}>
|
||||
<MemoryRouter>
|
||||
<ReferralCodeOwner {...props} />
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
};
|
||||
|
||||
describe('ReferralCodeOwner', () => {
|
||||
it('should render loading state', () => {
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: ExplorerReferralCodeOwnerDocument,
|
||||
variables: {
|
||||
id: 'ABC123',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
||||
|
||||
expect(getByText('Loading...')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render error state', async () => {
|
||||
const errorMessage = 'Error fetching referrer: ABC123';
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: ExplorerReferralCodeOwnerDocument,
|
||||
variables: {
|
||||
id: 'ABC123',
|
||||
},
|
||||
},
|
||||
error: new Error('nope'),
|
||||
},
|
||||
];
|
||||
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(errorMessage)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should render link to referring party', async () => {
|
||||
const referrerId = 'DEF789';
|
||||
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: ExplorerReferralCodeOwnerDocument,
|
||||
variables: {
|
||||
id: 'ABC123',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
referralSets: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
__typename: 'ReferralSet',
|
||||
referrer: referrerId,
|
||||
createdAt: '123',
|
||||
updatedAt: '456',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(referrerId)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { TableCell } from '../../../table';
|
||||
import { useExplorerReferralCodeOwnerQuery } from './__generated__/code-owner';
|
||||
import { PartyLink } from '../../../links';
|
||||
|
||||
export interface ReferralCodeOwnerProps {
|
||||
code: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the owner of a referral code
|
||||
*/
|
||||
export const ReferralCodeOwner = ({ code }: ReferralCodeOwnerProps) => {
|
||||
const { data, error, loading } = useExplorerReferralCodeOwnerQuery({
|
||||
variables: {
|
||||
id: code,
|
||||
},
|
||||
});
|
||||
const referrer = data?.referralSets.edges[0]?.node.referrer || '';
|
||||
return (
|
||||
<TableCell>
|
||||
{loading && 'Loading...'}
|
||||
{error && `Error fetching referrer: ${code}`}
|
||||
{referrer.length > 0 && <PartyLink id={referrer} />}
|
||||
</TableCell>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { ReferralTeam } from './team';
|
||||
import type { CreateReferralSet } from './team';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
|
||||
describe('ReferralTeam', () => {
|
||||
const team = {
|
||||
name: 'Test Team',
|
||||
teamUrl: 'https://example.com/team',
|
||||
avatarUrl: 'https://example.com/avatar',
|
||||
closed: false,
|
||||
};
|
||||
|
||||
const mockTx: CreateReferralSet = {
|
||||
team,
|
||||
};
|
||||
|
||||
const mockId = '123456';
|
||||
const mockCreator = 'JohnDoe';
|
||||
|
||||
it('should render the team name', () => {
|
||||
const { getByText } = render(
|
||||
<MockedProvider>
|
||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(getByText('Test Team')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the team ID', () => {
|
||||
const { getByText } = render(
|
||||
<MockedProvider>
|
||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(getByText('Id')).toBeInTheDocument();
|
||||
expect(getByText(mockId)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the creator', () => {
|
||||
const { getByText } = render(
|
||||
<MockedProvider>
|
||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(getByText('Creator')).toBeInTheDocument();
|
||||
expect(getByText(mockCreator)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the team URL', () => {
|
||||
const { getByText } = render(
|
||||
<MockedProvider>
|
||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(getByText('Team URL')).toBeInTheDocument();
|
||||
expect(getByText(team.teamUrl)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the avatar URL', () => {
|
||||
const { getByText } = render(
|
||||
<MockedProvider>
|
||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(getByText('Avatar')).toBeInTheDocument();
|
||||
expect(getByText(team.avatarUrl)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the open status as a tick if closed is falsy', () => {
|
||||
const { getByTestId } = render(
|
||||
<MockedProvider>
|
||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(getByTestId('open-yes')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the open status as a cross if it is truthy', () => {
|
||||
const m = {
|
||||
team: {
|
||||
closed: true,
|
||||
},
|
||||
};
|
||||
|
||||
const { getByTestId } = render(
|
||||
<MockedProvider>
|
||||
<ReferralTeam tx={m} id={mockId} creator={mockCreator} />
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(getByTestId('open-no')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
import {
|
||||
VegaIcon,
|
||||
Icon,
|
||||
KeyValueTable,
|
||||
KeyValueTableRow,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import Hash from '../../../links/hash';
|
||||
import { t } from 'i18next';
|
||||
import { PartyLink } from '../../../links';
|
||||
|
||||
export type CreateReferralSet = components['schemas']['v1CreateReferralSet'];
|
||||
export type ReferralTeam = CreateReferralSet['team'];
|
||||
|
||||
export interface ReferralTeamProps {
|
||||
tx: CreateReferralSet;
|
||||
id: string;
|
||||
creator: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the details for a team in a CreateReferralSet or UpdateReferralSet transaction.
|
||||
*
|
||||
* Intentionally does not render the avatar image or link to the team url.
|
||||
*/
|
||||
export const ReferralTeam = ({ tx, id, creator }: ReferralTeamProps) => {
|
||||
if (!tx.team) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<div className="inline-block mr-2 leading-none">
|
||||
<VegaIcon name={VegaIconNames.TEAM} />
|
||||
</div>
|
||||
{tx.team.name && (
|
||||
<h3 className="inline-block leading-loose">{tx.team.name}</h3>
|
||||
)}
|
||||
|
||||
<div className="min-w-fit max-w-2xl block">
|
||||
<KeyValueTable>
|
||||
<KeyValueTableRow>
|
||||
{t('Id')}
|
||||
<Hash text={id} truncate={false} />
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow>
|
||||
{t('Creator')}
|
||||
<PartyLink id={creator} truncate={false} />
|
||||
</KeyValueTableRow>
|
||||
{tx.team.teamUrl && (
|
||||
<KeyValueTableRow>
|
||||
{t('Team URL')}
|
||||
<Hash text={tx.team.teamUrl} truncate={false} />
|
||||
</KeyValueTableRow>
|
||||
)}
|
||||
{tx.team.avatarUrl && (
|
||||
<KeyValueTableRow>
|
||||
{t('Avatar')}
|
||||
<Hash text={tx.team.avatarUrl} truncate={false} />
|
||||
</KeyValueTableRow>
|
||||
)}
|
||||
<KeyValueTableRow>
|
||||
{t('Open')}
|
||||
<span data-testid={!tx.team.closed ? 'open-yes' : 'open-no'}>
|
||||
{!tx.team.closed ? <Icon name="tick" /> : <Icon name="cross" />}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
</KeyValueTable>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -27,7 +27,8 @@ export const sharedHeaderProps = {
|
||||
className: 'align-top',
|
||||
};
|
||||
|
||||
const Labels: Record<BlockExplorerTransactionResult['type'], string> = {
|
||||
// The incoming type field is usually the right thing to show. Exceptions are listed here
|
||||
const LabelOverrides: Record<BlockExplorerTransactionResult['type'], string> = {
|
||||
'Stop Orders Submission': 'Stop Order',
|
||||
'Stop Orders Cancellation': 'Cancel Stop Order',
|
||||
};
|
||||
@@ -50,7 +51,7 @@ export const TxDetailsShared = ({
|
||||
const time: string = blockData?.result.block.header.time || '';
|
||||
const height: string = blockData?.result.block.header.height || txData.block;
|
||||
|
||||
const type = Labels[txData.type] || txData.type;
|
||||
const type = LabelOverrides[txData.type] || txData.type;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
import { ReferralCodeOwner } from './referrals/referral-code-owner';
|
||||
|
||||
interface TxDetailsApplyReferralCodeProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
pubKey: string | undefined;
|
||||
blockData: TendermintBlocksResponse | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
||||
*/
|
||||
export const TxDetailsApplyReferralCode = ({
|
||||
txData,
|
||||
pubKey,
|
||||
blockData,
|
||||
}: TxDetailsApplyReferralCodeProps) => {
|
||||
if (!txData || !txData.command.applyReferralCode || !txData.signature) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
}
|
||||
|
||||
const referralCode = txData.command.applyReferralCode.id;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||
<TxDetailsShared
|
||||
txData={txData}
|
||||
pubKey={pubKey}
|
||||
blockData={blockData}
|
||||
/>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Applied Code')}</TableCell>
|
||||
<TableCell>{referralCode}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Referrer')}</TableCell>
|
||||
<ReferralCodeOwner code={referralCode} />
|
||||
</TableRow>
|
||||
</TableWithTbody>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||
import { ReferralTeam } from './referrals/team';
|
||||
|
||||
interface TxDetailsCreateReferralProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
pubKey: string | undefined;
|
||||
blockData: TendermintBlocksResponse | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
||||
*/
|
||||
export const TxDetailsCreateReferralSet = ({
|
||||
txData,
|
||||
pubKey,
|
||||
blockData,
|
||||
}: TxDetailsCreateReferralProps) => {
|
||||
if (!txData || !txData.command.createReferralSet || !txData.signature) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
}
|
||||
|
||||
const id = txSignatureToDeterministicId(txData.signature.value);
|
||||
|
||||
const isTeam = txData.command.createReferralSet.isTeam || false;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||
<TxDetailsShared
|
||||
txData={txData}
|
||||
pubKey={pubKey}
|
||||
blockData={blockData}
|
||||
/>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{isTeam ? t('Team ID') : t('Referral code')}</TableCell>
|
||||
<TableCell>{id}</TableCell>
|
||||
</TableRow>
|
||||
</TableWithTbody>
|
||||
|
||||
<ReferralTeam
|
||||
tx={txData.command.createReferralSet}
|
||||
id={id}
|
||||
creator={txData.submitter}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -28,6 +28,10 @@ import { TxProposal } from './tx-proposal';
|
||||
import { TxDetailsTransfer } from './tx-transfer';
|
||||
import { TxDetailsStopOrderSubmission } from './tx-stop-order-submission';
|
||||
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
|
||||
import { TxDetailsCreateReferralSet } from './tx-create-referral-set';
|
||||
import { TxDetailsApplyReferralCode } from './tx-apply-referral-code';
|
||||
import { TxDetailsUpdateReferralSet } from './tx-update-referral-set';
|
||||
import { TxDetailsJoinTeam } from './tx-join-team';
|
||||
|
||||
interface TxDetailsWrapperProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
@@ -121,6 +125,14 @@ function getTransactionComponent(txData?: BlockExplorerTransactionResult) {
|
||||
return TxDetailsStopOrderSubmission;
|
||||
case 'Transfer Funds':
|
||||
return TxDetailsTransfer;
|
||||
case 'Create Referral Set':
|
||||
return TxDetailsCreateReferralSet;
|
||||
case 'Update Referral Set':
|
||||
return TxDetailsUpdateReferralSet;
|
||||
case 'Apply Referral Code':
|
||||
return TxDetailsApplyReferralCode;
|
||||
case 'Join Team':
|
||||
return TxDetailsJoinTeam;
|
||||
default:
|
||||
return TxDetailsGeneric;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
import { ReferralCodeOwner } from './referrals/referral-code-owner';
|
||||
|
||||
interface TxDetailsJoinTeamProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
pubKey: string | undefined;
|
||||
blockData: TendermintBlocksResponse | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
||||
*/
|
||||
export const TxDetailsJoinTeam = ({
|
||||
txData,
|
||||
pubKey,
|
||||
blockData,
|
||||
}: TxDetailsJoinTeamProps) => {
|
||||
if (!txData || !txData.command.joinTeam || !txData.signature) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
}
|
||||
|
||||
const team = txData.command.joinTeam.id;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||
<TxDetailsShared
|
||||
txData={txData}
|
||||
pubKey={pubKey}
|
||||
blockData={blockData}
|
||||
/>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Team')}</TableCell>
|
||||
<TableCell>{team}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Referrer')}</TableCell>
|
||||
<ReferralCodeOwner code={team} />
|
||||
</TableRow>
|
||||
</TableWithTbody>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||
import { ReferralTeam } from './referrals/team';
|
||||
|
||||
interface TxDetailsUpdateReferralProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
pubKey: string | undefined;
|
||||
blockData: TendermintBlocksResponse | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A copy of create referral set, effectively.
|
||||
* Updating a referral set without a team doesn't make sense,
|
||||
* but is valid, so this component ignores sense.
|
||||
*/
|
||||
export const TxDetailsUpdateReferralSet = ({
|
||||
txData,
|
||||
pubKey,
|
||||
blockData,
|
||||
}: TxDetailsUpdateReferralProps) => {
|
||||
if (!txData || !txData.command.updateReferralSet || !txData.signature) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
}
|
||||
|
||||
const id = txSignatureToDeterministicId(txData.signature.value);
|
||||
|
||||
const isTeam = txData.command.updateReferralSet.isTeam || false;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||
<TxDetailsShared
|
||||
txData={txData}
|
||||
pubKey={pubKey}
|
||||
blockData={blockData}
|
||||
/>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{isTeam ? t('Team ID') : t('Referral code')}</TableCell>
|
||||
<TableCell>{id}</TableCell>
|
||||
</TableRow>
|
||||
</TableWithTbody>
|
||||
|
||||
<ReferralTeam
|
||||
tx={txData.command.updateReferralSet}
|
||||
id={id}
|
||||
creator={txData.submitter}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -28,6 +28,7 @@ export type FilterOption =
|
||||
| 'Delegate'
|
||||
| 'Ethereum Key Rotate Submission'
|
||||
| 'Issue Signatures'
|
||||
| 'Join Team'
|
||||
| 'Key Rotate Submission'
|
||||
| 'Liquidity Provision Order'
|
||||
| 'Node Signature'
|
||||
@@ -47,45 +48,46 @@ export type FilterOption =
|
||||
| 'Vote on Proposal'
|
||||
| 'Withdraw';
|
||||
|
||||
// Alphabetised list of transaction types to appear at the top level
|
||||
export const PrimaryFilterOptions: FilterOption[] = [
|
||||
'Amend LiquidityProvision Order',
|
||||
'Amend Order',
|
||||
'Batch Market Instructions',
|
||||
'Cancel LiquidityProvision Order',
|
||||
'Cancel Order',
|
||||
'Cancel Transfer Funds',
|
||||
'Delegate',
|
||||
'Liquidity Provision Order',
|
||||
'Proposal',
|
||||
'Stop Orders Submission',
|
||||
'Stop Orders Cancellation',
|
||||
'Submit Oracle Data',
|
||||
'Submit Order',
|
||||
'Transfer Funds',
|
||||
'Undelegate',
|
||||
'Vote on Proposal',
|
||||
'Withdraw',
|
||||
];
|
||||
export const filterOptions: Record<string, FilterOption[]> = {
|
||||
'Market Instructions': [
|
||||
'Amend LiquidityProvision Order',
|
||||
'Amend Order',
|
||||
'Batch Market Instructions',
|
||||
'Cancel LiquidityProvision Order',
|
||||
'Cancel Order',
|
||||
'Liquidity Provision Order',
|
||||
'Stop Orders Submission',
|
||||
'Stop Orders Cancellation',
|
||||
'Submit Order',
|
||||
],
|
||||
'Transfers and Withdrawals': [
|
||||
'Transfer Funds',
|
||||
'Cancel Transfer Funds',
|
||||
'Withdraw',
|
||||
],
|
||||
Governance: ['Delegate', 'Undelegate', 'Vote on Proposal', 'Proposal'],
|
||||
Referrals: [
|
||||
'Apply Referral Code',
|
||||
'Create Referral Set',
|
||||
'Join Team',
|
||||
'Update Referral Set',
|
||||
],
|
||||
'External Data': ['Chain Event', 'Submit Oracle Data'],
|
||||
Validators: [
|
||||
'Ethereum Key Rotate Submission',
|
||||
'Issue Signatures',
|
||||
'Key Rotate Submission',
|
||||
'Node Signature',
|
||||
'Node Vote',
|
||||
'Protocol Upgrade',
|
||||
'Register new Node',
|
||||
'State Variable Proposal',
|
||||
'Validator Heartbeat',
|
||||
],
|
||||
};
|
||||
|
||||
// Alphabetised list of transaction types to nest under a 'More...' submenu
|
||||
export const SecondaryFilterOptions: FilterOption[] = [
|
||||
'Chain Event',
|
||||
'Ethereum Key Rotate Submission',
|
||||
'Issue Signatures',
|
||||
'Key Rotate Submission',
|
||||
'Node Signature',
|
||||
'Node Vote',
|
||||
'Protocol Upgrade',
|
||||
'Register new Node',
|
||||
'State Variable Proposal',
|
||||
'Validator Heartbeat',
|
||||
];
|
||||
|
||||
export const AllFilterOptions: FilterOption[] = [
|
||||
...PrimaryFilterOptions,
|
||||
...SecondaryFilterOptions,
|
||||
];
|
||||
export const AllFilterOptions: FilterOption[] =
|
||||
Object.values(filterOptions).flat();
|
||||
|
||||
export interface TxFilterProps {
|
||||
filters: Set<FilterOption>;
|
||||
@@ -122,46 +124,33 @@ export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
{PrimaryFilterOptions.map((f) => (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={f}
|
||||
checked={filters.has(f)}
|
||||
onCheckedChange={() => {
|
||||
// NOTE: These act like radio buttons until the API supports multiple filters
|
||||
setFilters(new Set([f]));
|
||||
}}
|
||||
id={`radio-${f}`}
|
||||
>
|
||||
{f}
|
||||
<DropdownMenuItemIndicator>
|
||||
<Icon name="tick-circle" />
|
||||
</DropdownMenuItemIndicator>
|
||||
</DropdownMenuCheckboxItem>
|
||||
|
||||
{Object.entries(filterOptions).map(([key, value]) => (
|
||||
<DropdownMenuSub key={key}>
|
||||
<DropdownMenuSubTrigger>
|
||||
{t(key)}
|
||||
<Icon name="chevron-right" />
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent>
|
||||
{value.map((f) => (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={f}
|
||||
checked={filters.has(f)}
|
||||
onCheckedChange={(checked) => {
|
||||
// NOTE: These act like radio buttons until the API supports multiple filters
|
||||
setFilters(new Set([f]));
|
||||
}}
|
||||
id={`radio-${f}`}
|
||||
>
|
||||
{f}
|
||||
<DropdownMenuItemIndicator>
|
||||
<Icon name="tick-circle" className="inline" />
|
||||
</DropdownMenuItemIndicator>
|
||||
</DropdownMenuCheckboxItem>
|
||||
))}
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
))}
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
{t('More Types')}
|
||||
<Icon name="chevron-right" />
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent>
|
||||
{SecondaryFilterOptions.map((f) => (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={f}
|
||||
checked={filters.has(f)}
|
||||
onCheckedChange={(checked) => {
|
||||
// NOTE: These act like radio buttons until the API supports multiple filters
|
||||
setFilters(new Set([f]));
|
||||
}}
|
||||
id={`radio-${f}`}
|
||||
>
|
||||
{f}
|
||||
<DropdownMenuItemIndicator>
|
||||
<Icon name="tick-circle" className="inline" />
|
||||
</DropdownMenuItemIndicator>
|
||||
</DropdownMenuCheckboxItem>
|
||||
))}
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
||||
@@ -48,6 +48,8 @@ const displayString: StringMap = {
|
||||
StopOrdersSubmission: 'Stop',
|
||||
StopOrdersCancellation: 'Cancel stop',
|
||||
'Stop Orders Cancellation': 'Cancel stop',
|
||||
'Apply Referral Code': 'Referral',
|
||||
'Create Referral Set': 'Create referral',
|
||||
};
|
||||
|
||||
export function getLabelForStopOrderType(
|
||||
|
||||
@@ -31,6 +31,10 @@ const Tx = () => {
|
||||
}
|
||||
}
|
||||
|
||||
if (!data || !data?.transaction) {
|
||||
errorMessage = 'Transaction not found';
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<PageHeader
|
||||
@@ -49,7 +53,7 @@ const Tx = () => {
|
||||
<TxDetails
|
||||
className="mb-28"
|
||||
txData={data?.transaction}
|
||||
pubKey={data?.transaction.submitter}
|
||||
pubKey={data?.transaction?.submitter}
|
||||
/>
|
||||
</RenderFetched>
|
||||
</section>
|
||||
|
||||
@@ -11,8 +11,8 @@ interface TxDetailsProps {
|
||||
export const txDetailsTruncateLength = 30;
|
||||
|
||||
export const TxDetails = ({ txData, pubKey }: TxDetailsProps) => {
|
||||
if (!txData) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
if (!txData || !pubKey) {
|
||||
return <>{t('Transaction could not be found')}</>;
|
||||
}
|
||||
return (
|
||||
<section className="mb-10" key={txData.hash}>
|
||||
|
||||
+2
-2
@@ -8,13 +8,13 @@ type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
||||
type XOR<T, U> = T | U extends object
|
||||
? (Without<T, U> & U) | (Without<U, T> & T)
|
||||
: T | U;
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
type OneOf<T extends any[]> = T extends [infer Only]
|
||||
? Only
|
||||
: T extends [infer A, infer B, ...infer Rest]
|
||||
? OneOf<[XOR<A, B>, ...Rest]>
|
||||
: never;
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
|
||||
export interface paths {
|
||||
'/info': {
|
||||
|
||||
@@ -47,7 +47,7 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
|
||||
.and('contain.text', 'USDC (fake)');
|
||||
});
|
||||
|
||||
it('Unable to submit proposal with public key', function () {
|
||||
it.skip('Unable to submit proposal with public key', function () {
|
||||
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
|
||||
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
@@ -55,7 +55,10 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
|
||||
cy.getByTestId('dialog-content')
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get('h1').should('have.text', 'Transaction failed');
|
||||
cy.getByTestId('dialog-title').should(
|
||||
'have.text',
|
||||
'Transaction failed'
|
||||
);
|
||||
cy.getByTestId('Error').should('have.text', expectedErrorTxt);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -112,6 +112,7 @@ export function createNewMarketProposalTxBody(): ProposalSubmissionBody {
|
||||
performanceHysteresisEpochs: 2,
|
||||
slaCompetitionFactor: '0.1',
|
||||
},
|
||||
// FIXME: workaround because of https://github.com/vegaprotocol/vega/issues/10343
|
||||
quadraticSlippageFactor: '0',
|
||||
instrument: {
|
||||
name: 'Token test market',
|
||||
@@ -196,6 +197,7 @@ export function createNewMarketProposalTxBody(): ProposalSubmissionBody {
|
||||
timeWindow: '3600',
|
||||
scalingFactor: 10,
|
||||
},
|
||||
// FIXME: workaround because of https://github.com/vegaprotocol/vega/issues/10343
|
||||
triggeringRatio: '0.7',
|
||||
auctionExtension: '1',
|
||||
},
|
||||
@@ -240,6 +242,7 @@ export function createSuccessorMarketProposalTxBody(
|
||||
decimalPlaces: '5',
|
||||
positionDecimalPlaces: '5',
|
||||
linearSlippageFactor: '0.001',
|
||||
// FIXME: workaround because of https://github.com/vegaprotocol/vega/issues/10343
|
||||
quadraticSlippageFactor: '0',
|
||||
liquiditySlaParameters: {
|
||||
priceRange: '0.5',
|
||||
@@ -334,6 +337,7 @@ export function createSuccessorMarketProposalTxBody(
|
||||
timeWindow: '3600',
|
||||
scalingFactor: 10,
|
||||
},
|
||||
// FIXME: workaround because of https://github.com/vegaprotocol/vega/issues/10343
|
||||
triggeringRatio: '0.7',
|
||||
auctionExtension: '1',
|
||||
},
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
} from '@vegaprotocol/web3';
|
||||
import { Web3Provider } from '@vegaprotocol/web3';
|
||||
import { VegaWalletDialogs } from './components/vega-wallet-dialogs';
|
||||
import { VegaWalletProvider } from '@vegaprotocol/wallet';
|
||||
import { VegaWalletProvider, useChainId } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
useVegaTransactionManager,
|
||||
useVegaTransactionUpdater,
|
||||
@@ -96,7 +96,9 @@ const cache: InMemoryCacheConfig = {
|
||||
const Web3Container = ({
|
||||
chainId,
|
||||
}: {
|
||||
/** Ethereum chain id */
|
||||
chainId: number;
|
||||
/** Ethereum provider url */
|
||||
providerUrl: string;
|
||||
}) => {
|
||||
const InitializeHandlers = () => {
|
||||
@@ -123,6 +125,9 @@ const Web3Container = ({
|
||||
MOZILLA_EXTENSION_URL,
|
||||
VEGA_WALLET_URL,
|
||||
} = useEnvironment();
|
||||
|
||||
const vegaChainId = useChainId(VEGA_URL);
|
||||
|
||||
useEffect(() => {
|
||||
if (chainId) {
|
||||
return initializeConnectors(
|
||||
@@ -157,7 +162,8 @@ const Web3Container = ({
|
||||
!VEGA_EXPLORER_URL ||
|
||||
!DocsLinks ||
|
||||
!CHROME_EXTENSION_URL ||
|
||||
!MOZILLA_EXTENSION_URL
|
||||
!MOZILLA_EXTENSION_URL ||
|
||||
!vegaChainId
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
@@ -169,6 +175,7 @@ const Web3Container = ({
|
||||
config={{
|
||||
network: VEGA_ENV,
|
||||
vegaUrl: VEGA_URL,
|
||||
chainId: vegaChainId,
|
||||
vegaWalletServiceUrl: VEGA_WALLET_URL,
|
||||
links: {
|
||||
explorer: VEGA_EXPLORER_URL,
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ describe('Proposal header', () => {
|
||||
screen.queryByTestId('proposal-description')
|
||||
).not.toBeInTheDocument();
|
||||
expect(screen.getByTestId('proposal-details')).toHaveTextContent(
|
||||
'Market change: MarketId'
|
||||
'Update to market ID: MarketId'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
+42
-4
@@ -1,5 +1,11 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Lozenge, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
CopyWithTooltip,
|
||||
Lozenge,
|
||||
Tooltip,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { shorten } from '@vegaprotocol/utils';
|
||||
import { Heading, SubHeading } from '../../../../components/heading';
|
||||
import type { ReactNode } from 'react';
|
||||
@@ -12,7 +18,12 @@ import {
|
||||
useNewTransferProposalDetails,
|
||||
useSuccessorMarketProposalDetails,
|
||||
} from '@vegaprotocol/proposals';
|
||||
import { useFeatureFlags } from '@vegaprotocol/environment';
|
||||
import {
|
||||
CONSOLE_MARKET_PAGE,
|
||||
DApp,
|
||||
useFeatureFlags,
|
||||
useLinks,
|
||||
} from '@vegaprotocol/environment';
|
||||
import Routes from '../../../routes';
|
||||
import { Link } from 'react-router-dom';
|
||||
import type { VoteState } from '../vote-details/use-user-vote';
|
||||
@@ -32,6 +43,8 @@ export const ProposalHeader = ({
|
||||
const { t } = useTranslation();
|
||||
const change = proposal?.terms.change;
|
||||
|
||||
const consoleLink = useLinks(DApp.Console);
|
||||
|
||||
let details: ReactNode;
|
||||
let proposalType = '';
|
||||
let fallbackTitle = '';
|
||||
@@ -106,8 +119,33 @@ export const ProposalHeader = ({
|
||||
fallbackTitle = t('UpdateMarketProposal');
|
||||
details = (
|
||||
<>
|
||||
<span>{t('MarketChange')}:</span>{' '}
|
||||
<span>{truncateMiddle(change.marketId)}</span>
|
||||
<span>{t('UpdateToMarket')}:</span>{' '}
|
||||
<span className="inline-flex items-start gap-2">
|
||||
<span className="break-all">{change.marketId} </span>
|
||||
<span className="inline-flex items-end gap-0">
|
||||
<CopyWithTooltip
|
||||
text={change.marketId}
|
||||
description={t('copyToClipboard')}
|
||||
>
|
||||
<button className="inline-block px-1">
|
||||
<VegaIcon size={20} name={VegaIconNames.COPY} />
|
||||
</button>
|
||||
</CopyWithTooltip>
|
||||
<Tooltip description={t('OpenInConsole')} align="center">
|
||||
<button
|
||||
className="inline-block px-1"
|
||||
onClick={() => {
|
||||
const marketPageLink = consoleLink(
|
||||
CONSOLE_MARKET_PAGE.replace(':marketId', change.marketId)
|
||||
);
|
||||
window.open(marketPageLink, '_blank');
|
||||
}}
|
||||
>
|
||||
<VegaIcon size={20} name={VegaIconNames.OPEN_EXTERNAL} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -48,6 +48,7 @@ const vegaWalletConfig: VegaWalletConfig = {
|
||||
chromeExtensionUrl: 'chrome',
|
||||
mozillaExtensionUrl: 'mozilla',
|
||||
},
|
||||
chainId: 'VEGA_CHAIN_ID',
|
||||
};
|
||||
|
||||
const renderComponent = (proposal: ProposalQuery['proposal']) => {
|
||||
|
||||
@@ -205,7 +205,6 @@ query Proposal(
|
||||
}
|
||||
}
|
||||
liquidityMonitoringParameters {
|
||||
triggeringRatio
|
||||
targetStakeParameters {
|
||||
timeWindow
|
||||
scalingFactor
|
||||
@@ -213,7 +212,6 @@ query Proposal(
|
||||
}
|
||||
positionDecimalPlaces
|
||||
linearSlippageFactor
|
||||
quadraticSlippageFactor
|
||||
}
|
||||
... on UpdateMarket {
|
||||
marketId
|
||||
@@ -366,7 +364,6 @@ query Proposal(
|
||||
}
|
||||
}
|
||||
liquidityMonitoringParameters {
|
||||
triggeringRatio
|
||||
targetStakeParameters {
|
||||
timeWindow
|
||||
scalingFactor
|
||||
|
||||
File diff suppressed because one or more lines are too long
+2
-2
@@ -16,7 +16,7 @@ import type { ValidatorsView } from './validator-tables';
|
||||
const nodeFactory = (
|
||||
overrides?: PartialDeep<NodesFragmentFragment>
|
||||
): NodesFragmentFragment => {
|
||||
const defaultNode = {
|
||||
const defaultNode: NodesFragmentFragment = {
|
||||
id: 'ccc022b7e63a4d0a6d3a193c3940c88574060e58a184964c994998d86835a1b4',
|
||||
name: 'high',
|
||||
avatarUrl: 'https://upload.wikimedia.org/wikipedia/en/2/25/Marvin-TV-3.jpg',
|
||||
@@ -288,7 +288,7 @@ describe('Consensus validators table', () => {
|
||||
|
||||
expect(
|
||||
grid.querySelector('[role="gridcell"][col-id="totalPenalties"]')
|
||||
).toHaveTextContent('10.07%');
|
||||
).toHaveTextContent('13.16%');
|
||||
|
||||
expect(
|
||||
grid.querySelector('[role="gridcell"][col-id="normalisedVotingPower"]')
|
||||
|
||||
+11
-2
@@ -185,6 +185,15 @@ export const ConsensusValidatorsTable = ({
|
||||
const { rawValidatorScore: previousEpochValidatorScore } =
|
||||
getLastEpochScoreAndPerformance(previousEpochData, id);
|
||||
|
||||
const overstakingPenalty = calculateOverallPenalty(
|
||||
id,
|
||||
allNodesInPreviousEpoch
|
||||
);
|
||||
const totalPenalty = calculateOverstakedPenalty(
|
||||
id,
|
||||
allNodesInPreviousEpoch
|
||||
);
|
||||
|
||||
return {
|
||||
id,
|
||||
[ValidatorFields.RANKING_INDEX]: stakedTotalRanking,
|
||||
@@ -213,11 +222,11 @@ export const ConsensusValidatorsTable = ({
|
||||
2
|
||||
),
|
||||
[ValidatorFields.OVERSTAKING_PENALTY]: formatNumberPercentage(
|
||||
calculateOverstakedPenalty(id, allNodesInPreviousEpoch),
|
||||
overstakingPenalty,
|
||||
2
|
||||
),
|
||||
[ValidatorFields.TOTAL_PENALTIES]: formatNumberPercentage(
|
||||
calculateOverallPenalty(id, allNodesInPreviousEpoch),
|
||||
totalPenalty,
|
||||
2
|
||||
),
|
||||
[ValidatorFields.PENDING_STAKE]: pendingStake,
|
||||
|
||||
+11
-2
@@ -124,6 +124,15 @@ export const StandbyPendingValidatorsTable = ({
|
||||
}
|
||||
}
|
||||
|
||||
const overstakingPenalty = calculateOverallPenalty(
|
||||
id,
|
||||
allNodesInPreviousEpoch
|
||||
);
|
||||
const totalPenalty = calculateOverstakedPenalty(
|
||||
id,
|
||||
allNodesInPreviousEpoch
|
||||
);
|
||||
|
||||
return {
|
||||
id,
|
||||
[ValidatorFields.RANKING_INDEX]: stakedTotalRanking,
|
||||
@@ -154,11 +163,11 @@ export const StandbyPendingValidatorsTable = ({
|
||||
2
|
||||
),
|
||||
[ValidatorFields.OVERSTAKING_PENALTY]: formatNumberPercentage(
|
||||
calculateOverstakedPenalty(id, allNodesInPreviousEpoch),
|
||||
overstakingPenalty,
|
||||
2
|
||||
),
|
||||
[ValidatorFields.TOTAL_PENALTIES]: formatNumberPercentage(
|
||||
calculateOverallPenalty(id, allNodesInPreviousEpoch),
|
||||
totalPenalty,
|
||||
2
|
||||
),
|
||||
[ValidatorFields.PENDING_STAKE]: pendingStake,
|
||||
|
||||
@@ -266,7 +266,9 @@ export const ValidatorTable = ({
|
||||
|
||||
<Tooltip description={t('OverstakedPenaltyDescription')}>
|
||||
<span data-testid="overstaking-penalty">
|
||||
{formatNumberPercentage(penalties.overstaked, 2)}
|
||||
{penalties.overstaked
|
||||
? formatNumberPercentage(penalties.overstaked, 2)
|
||||
: '-'}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</KeyValueTableRow>
|
||||
@@ -285,7 +287,9 @@ export const ValidatorTable = ({
|
||||
</span>
|
||||
<span data-testid="total-penalties">
|
||||
<strong>
|
||||
{formatNumberPercentage(penalties.overall, 2)}
|
||||
{penalties.overall
|
||||
? formatNumberPercentage(penalties.overall, 2)
|
||||
: '-'}
|
||||
</strong>
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
|
||||
@@ -3,11 +3,11 @@ import {
|
||||
getLastEpochScoreAndPerformance,
|
||||
getNormalisedVotingPower,
|
||||
getUnnormalisedVotingPower,
|
||||
getOverstakingPenalty,
|
||||
getFormattedPerformanceScore,
|
||||
getPerformancePenalty,
|
||||
getTotalPenalties,
|
||||
getStakePercentage,
|
||||
calculateOverallPenalty,
|
||||
calculateOverstakedPenalty,
|
||||
} from './shared';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
@@ -106,38 +106,6 @@ describe('getUnnormalisedVotingPower', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOverstakingPenalty', () => {
|
||||
it('returns "0%" when both arguments are null or undefined', () => {
|
||||
expect(getOverstakingPenalty(null, null)).toBe('0%');
|
||||
expect(getOverstakingPenalty(undefined, undefined)).toBe('0%');
|
||||
expect(getOverstakingPenalty(null, undefined)).toBe('0%');
|
||||
expect(getOverstakingPenalty(undefined, null)).toBe('0%');
|
||||
});
|
||||
|
||||
it('returns "0%" when one argument is null or undefined', () => {
|
||||
expect(getOverstakingPenalty('10', null)).toBe('0%');
|
||||
expect(getOverstakingPenalty(null, '20')).toBe('0%');
|
||||
expect(getOverstakingPenalty('10', undefined)).toBe('0%');
|
||||
expect(getOverstakingPenalty(undefined, '20')).toBe('0%');
|
||||
});
|
||||
|
||||
it('returns "0%" when validatorScore or stakeScore is zero', () => {
|
||||
expect(getOverstakingPenalty('0', '20')).toBe('0%');
|
||||
expect(getOverstakingPenalty('10', '0')).toBe('0%');
|
||||
});
|
||||
|
||||
it('returns the correct overstaking penalty', () => {
|
||||
expect(getOverstakingPenalty('0.18', '0.2')).toBe('10.00%');
|
||||
expect(getOverstakingPenalty('0.2', '0.2')).toBe('0.00%');
|
||||
expect(getOverstakingPenalty('0.04', '0.2')).toBe('80.00%');
|
||||
});
|
||||
|
||||
it('handles string numbers with decimals', () => {
|
||||
expect(getOverstakingPenalty('7.5', '15')).toBe('50.00%');
|
||||
expect(getOverstakingPenalty('12.5', '25')).toBe('50.00%');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFormattedPerformanceScore', () => {
|
||||
it('should return the formatted performance score', () => {
|
||||
expect(getFormattedPerformanceScore('0.25')).toEqual(new BigNumber(0.25));
|
||||
@@ -152,17 +120,6 @@ describe('getPerformancePenalty', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTotalPenalties', () => {
|
||||
it('should return the total penalties', () => {
|
||||
expect(getTotalPenalties('0.25', '1', '5000', '10000')).toEqual('50.00%');
|
||||
expect(getTotalPenalties('0.25', '0.5', '5000', '10000')).toEqual('75.00%');
|
||||
});
|
||||
|
||||
it('should return 0 if the total penalties is negative', () => {
|
||||
expect(getTotalPenalties('0.25', '0.5', '1000', '10000')).toEqual('0.00%');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getStakePercentage', () => {
|
||||
it('should return the stake percentage', () => {
|
||||
expect(
|
||||
@@ -182,3 +139,107 @@ describe('getStakePercentage', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculateOverallPenalty', () => {
|
||||
it('returns null if rewardScore is null', () => {
|
||||
const res = calculateOverallPenalty('1', [
|
||||
{
|
||||
id: '1',
|
||||
rewardScore: null,
|
||||
stakedTotal: '',
|
||||
rankingScore: {
|
||||
stakeScore: '0.25',
|
||||
performanceScore: '0.75',
|
||||
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
previousStatus:
|
||||
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
rankingScore: '',
|
||||
votingPower: '',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(res).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null if rewardScore.rawValidatorScore is null (should not happen)', () => {
|
||||
const res = calculateOverallPenalty('1', [
|
||||
{
|
||||
id: '1',
|
||||
stakedTotal: '',
|
||||
rewardScore: {
|
||||
rawValidatorScore: '0.25',
|
||||
performanceScore: '0.75',
|
||||
multisigScore: '',
|
||||
validatorScore: null as unknown as string,
|
||||
normalisedScore: '',
|
||||
validatorStatus:
|
||||
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
},
|
||||
rankingScore: {
|
||||
stakeScore: '0.25',
|
||||
performanceScore: '0.75',
|
||||
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
previousStatus:
|
||||
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
rankingScore: '',
|
||||
votingPower: '',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(res).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculateOverstakedPenalty', () => {
|
||||
it('returns null if rewardScore is null', () => {
|
||||
const res = calculateOverstakedPenalty('1', [
|
||||
{
|
||||
id: '1',
|
||||
rewardScore: null,
|
||||
stakedTotal: '',
|
||||
rankingScore: {
|
||||
stakeScore: '0.25',
|
||||
performanceScore: '0.75',
|
||||
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
previousStatus:
|
||||
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
rankingScore: '',
|
||||
votingPower: '',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(res).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null if rewardScore.rawValidatorScore is null (should not happen)', () => {
|
||||
const res = calculateOverstakedPenalty('1', [
|
||||
{
|
||||
id: '1',
|
||||
stakedTotal: '',
|
||||
rewardScore: {
|
||||
rawValidatorScore: null as unknown as string,
|
||||
performanceScore: '0.75',
|
||||
multisigScore: '',
|
||||
validatorScore: '',
|
||||
normalisedScore: '',
|
||||
validatorStatus:
|
||||
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
},
|
||||
rankingScore: {
|
||||
stakeScore: '0.25',
|
||||
performanceScore: '0.75',
|
||||
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
previousStatus:
|
||||
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
|
||||
rankingScore: '',
|
||||
votingPower: '',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(res).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
import type { PreviousEpochQuery } from './__generated__/PreviousEpoch';
|
||||
import { BigNumber } from '../../lib/bignumber';
|
||||
import type { LastArrayElement } from 'type-fest';
|
||||
import isNull from 'lodash/isNull';
|
||||
|
||||
type Node = NonNullable<
|
||||
LastArrayElement<
|
||||
@@ -21,7 +22,10 @@ type Node = NonNullable<
|
||||
* @returns Theoretical stake score for given node based on the staked total
|
||||
* of all node of the same type (status)
|
||||
*/
|
||||
const calculateTheoreticalStakeScore = (nodeId: string, nodes: Node[]) => {
|
||||
const calculateTheoreticalStakeScore = (
|
||||
nodeId: string,
|
||||
nodes: Node[]
|
||||
): BigNumber | null => {
|
||||
const node = nodes.find((n) => n.id === nodeId);
|
||||
if (!node) {
|
||||
return new BigNumber(0);
|
||||
@@ -42,14 +46,25 @@ const calculateTheoreticalStakeScore = (nodeId: string, nodes: Node[]) => {
|
||||
* @param nodes A collection of all nodes - needed to calculate theoretical stake score
|
||||
* @returns %
|
||||
*/
|
||||
export const calculateOverallPenalty = (nodeId: string, nodes: Node[]) => {
|
||||
export const calculateOverallPenalty = (
|
||||
nodeId: string,
|
||||
nodes: Node[]
|
||||
): BigNumber | null => {
|
||||
const node = nodes.find((n) => n.id === nodeId);
|
||||
const tts = calculateTheoreticalStakeScore(nodeId, nodes);
|
||||
if (!node || tts.isZero()) {
|
||||
if (
|
||||
!node ||
|
||||
isNull(tts) ||
|
||||
!node.rewardScore ||
|
||||
(node.rewardScore && isNull(node.rewardScore.validatorScore))
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
if (tts.isZero()) {
|
||||
return new BigNumber(0);
|
||||
}
|
||||
const penalty = new BigNumber(1)
|
||||
.minus(new BigNumber(node.rewardScore?.validatorScore || 0).dividedBy(tts))
|
||||
.minus(new BigNumber(node.rewardScore.validatorScore).dividedBy(tts))
|
||||
.times(100);
|
||||
return penalty.isLessThan(0) ? new BigNumber(0) : penalty;
|
||||
};
|
||||
@@ -60,10 +75,21 @@ export const calculateOverallPenalty = (nodeId: string, nodes: Node[]) => {
|
||||
* @param nodes A collection of all nodes - needed to calculate theoretical stake score
|
||||
* @returns %
|
||||
*/
|
||||
export const calculateOverstakedPenalty = (nodeId: string, nodes: Node[]) => {
|
||||
export const calculateOverstakedPenalty = (
|
||||
nodeId: string,
|
||||
nodes: Node[]
|
||||
): BigNumber | null => {
|
||||
const node = nodes.find((n) => n.id === nodeId);
|
||||
const tts = calculateTheoreticalStakeScore(nodeId, nodes);
|
||||
if (!node || tts.isZero()) {
|
||||
if (
|
||||
!node ||
|
||||
isNull(tts) ||
|
||||
isNull(node.rewardScore) ||
|
||||
(node.rewardScore && node.rewardScore.rawValidatorScore === null)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
if (tts.isZero()) {
|
||||
return new BigNumber(0);
|
||||
}
|
||||
const penalty = new BigNumber(1)
|
||||
@@ -78,7 +104,9 @@ export const calculateOverstakedPenalty = (nodeId: string, nodes: Node[]) => {
|
||||
* Calculates performance penalty based on the given performance score.
|
||||
* @returns %
|
||||
*/
|
||||
export const calculatesPerformancePenalty = (performanceScore: string) => {
|
||||
export const calculatesPerformancePenalty = (
|
||||
performanceScore: string
|
||||
): BigNumber => {
|
||||
const penalty = new BigNumber(1)
|
||||
.minus(new BigNumber(performanceScore))
|
||||
.times(100);
|
||||
@@ -123,60 +151,6 @@ export const getPerformancePenalty = (performanceScore?: string) =>
|
||||
2
|
||||
);
|
||||
|
||||
export const getOverstakingPenalty = (
|
||||
validatorScore: string | null | undefined,
|
||||
stakeScore: string | null | undefined
|
||||
) => {
|
||||
if (!validatorScore || !stakeScore) {
|
||||
return '0%';
|
||||
}
|
||||
|
||||
// avoid division by zero
|
||||
if (
|
||||
new BigNumber(validatorScore).isZero() ||
|
||||
new BigNumber(stakeScore).isZero()
|
||||
) {
|
||||
return '0%';
|
||||
}
|
||||
|
||||
return formatNumberPercentage(
|
||||
BigNumber.max(
|
||||
new BigNumber(1)
|
||||
.minus(
|
||||
new BigNumber(validatorScore).dividedBy(new BigNumber(stakeScore))
|
||||
)
|
||||
.times(100),
|
||||
new BigNumber(0)
|
||||
),
|
||||
2
|
||||
);
|
||||
};
|
||||
|
||||
export const getTotalPenalties = (
|
||||
rawValidatorScore: string | null | undefined,
|
||||
performanceScore: string | undefined,
|
||||
stakedOnNode: string,
|
||||
totalStake: string
|
||||
) => {
|
||||
const calc =
|
||||
rawValidatorScore &&
|
||||
performanceScore &&
|
||||
new BigNumber(totalStake).isGreaterThan(0)
|
||||
? new BigNumber(1).minus(
|
||||
new BigNumber(performanceScore)
|
||||
.times(new BigNumber(rawValidatorScore))
|
||||
.dividedBy(
|
||||
new BigNumber(stakedOnNode).dividedBy(new BigNumber(totalStake))
|
||||
)
|
||||
)
|
||||
: new BigNumber(0);
|
||||
|
||||
return formatNumberPercentage(
|
||||
calc.isPositive() ? calc.times(100) : new BigNumber(0),
|
||||
2
|
||||
);
|
||||
};
|
||||
|
||||
export const getStakePercentage = (total: BigNumber, stakedOnNode: BigNumber) =>
|
||||
total.isEqualTo(0) || stakedOnNode.isEqualTo(0)
|
||||
? '0%'
|
||||
|
||||
@@ -1,14 +1,50 @@
|
||||
import { ToastsContainer, useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
Intent,
|
||||
ToastsContainer,
|
||||
TradingButton,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
useToasts,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
useEthereumTransactionToasts,
|
||||
useEthereumWithdrawApprovalsToasts,
|
||||
useVegaTransactionToasts,
|
||||
useWalletDisconnectToastActions,
|
||||
useWalletDisconnectedToasts,
|
||||
} from '@vegaprotocol/web3';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const WalletDisconnectAdditionalContent = () => {
|
||||
const { t } = useTranslation();
|
||||
const { hideToast } = useWalletDisconnectToastActions();
|
||||
const openVegaWalletDialog = useVegaWalletDialogStore(
|
||||
(store) => store.openVegaWalletDialog
|
||||
);
|
||||
return (
|
||||
<p className="mt-2">
|
||||
<TradingButton
|
||||
data-testid="connect-vega-wallet"
|
||||
onClick={() => {
|
||||
hideToast();
|
||||
openVegaWalletDialog();
|
||||
}}
|
||||
size="small"
|
||||
intent={Intent.Danger}
|
||||
icon={<VegaIcon name={VegaIconNames.ARROW_RIGHT} size={14} />}
|
||||
>
|
||||
<span className="whitespace-nowrap uppercase">{t('Connect')}</span>
|
||||
</TradingButton>
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export const ToastsManager = () => {
|
||||
useVegaTransactionToasts();
|
||||
useEthereumTransactionToasts();
|
||||
useEthereumWithdrawApprovalsToasts();
|
||||
useWalletDisconnectedToasts(<WalletDisconnectAdditionalContent />);
|
||||
|
||||
const toasts = useToasts((store) => store.toasts);
|
||||
return <ToastsContainer order="desc" toasts={toasts} />;
|
||||
|
||||
+7
-2
@@ -22,7 +22,12 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
NX_ICEBERG_ORDERS=true
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
NX_METAMASK_SNAPS=true
|
||||
NX_REFERRALS=true
|
||||
NX_TEAM_COMPETITION=true
|
||||
# NX_DISABLE_CLOSE_POSITION=false
|
||||
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
|
||||
NX_CHARTING_LIBRARY_PATH=https://assets.vega.community/trading-view-bundle/v0.0.1/
|
||||
NX_CHARTING_LIBRARY_HASH=PDjWaqPFndDp+LCvqbKvntWriaqNzNpZ5i9R/BULzCg=
|
||||
|
||||
@@ -28,3 +28,6 @@ NX_REFERRALS=true
|
||||
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
|
||||
NX_CHARTING_LIBRARY_PATH=https://assets.vega.community/trading-view-bundle/v0.0.1/
|
||||
NX_CHARTING_LIBRARY_HASH=PDjWaqPFndDp+LCvqbKvntWriaqNzNpZ5i9R/BULzCg=
|
||||
|
||||
@@ -314,7 +314,7 @@ describe('Closed', () => {
|
||||
});
|
||||
|
||||
it('display market actions', async () => {
|
||||
// Use market with a succcessor 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
|
||||
const marketsWithSuccessorAndParent = [
|
||||
{
|
||||
|
||||
@@ -137,6 +137,8 @@ const ClosedMarketsDataGrid = ({
|
||||
headerName: t('Market'),
|
||||
field: 'code',
|
||||
cellRenderer: 'MarketCodeCell',
|
||||
width: 150,
|
||||
resizable: true,
|
||||
},
|
||||
{
|
||||
headerName: t('Status'),
|
||||
@@ -280,6 +282,7 @@ const ClosedMarketsDataGrid = ({
|
||||
return (
|
||||
<AgGrid
|
||||
rowData={rowData}
|
||||
defaultColDef={COL_DEFS.default}
|
||||
columnDefs={colDefs}
|
||||
getRowId={({ data }) => data.id}
|
||||
overlayNoRowsTemplate={error ? error.message : t('No markets')}
|
||||
|
||||
@@ -17,6 +17,7 @@ const defaultColDef = {
|
||||
filter: true,
|
||||
resizable: true,
|
||||
filterParams: { buttons: ['reset'] },
|
||||
minWidth: 120,
|
||||
};
|
||||
|
||||
const components = {
|
||||
|
||||
@@ -53,6 +53,7 @@ export const MarketsPage = () => {
|
||||
size="extra-small"
|
||||
data-testid="propose-new-market"
|
||||
href={externalLink}
|
||||
target="_blank"
|
||||
>
|
||||
{t('Propose a new market')}
|
||||
</TradingAnchorButton>
|
||||
|
||||
@@ -29,6 +29,7 @@ export const useColumnDefs = () => {
|
||||
{
|
||||
headerName: t('Market'),
|
||||
field: 'tradableInstrument.instrument.code',
|
||||
pinned: true,
|
||||
cellRenderer: ({
|
||||
value,
|
||||
data,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useT } from '../../lib/use-t';
|
||||
import { RewardsContainer } from '../../components/rewards-container';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
import { ErrorBoundary } from '../../components/error-boundary';
|
||||
import { TinyScroll } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const Rewards = () => {
|
||||
const t = useT();
|
||||
@@ -16,10 +17,10 @@ export const Rewards = () => {
|
||||
}, [updateTitle, title]);
|
||||
return (
|
||||
<ErrorBoundary feature="rewards">
|
||||
<div className="container mx-auto p-4">
|
||||
<TinyScroll className="p-4 max-h-full overflow-auto">
|
||||
<h1 className="px-4 pb-4 text-2xl">{title}</h1>
|
||||
<RewardsContainer />
|
||||
</div>
|
||||
</TinyScroll>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ import type { ReactNode } from 'react';
|
||||
import { Web3Provider } from './web3-provider';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { DataLoader } from './data-loader';
|
||||
import { useChainId } from '@vegaprotocol/wallet';
|
||||
|
||||
export const Bootstrapper = ({ children }: { children: ReactNode }) => {
|
||||
const t = useT();
|
||||
@@ -26,13 +27,16 @@ export const Bootstrapper = ({ children }: { children: ReactNode }) => {
|
||||
CHROME_EXTENSION_URL,
|
||||
} = useEnvironment();
|
||||
|
||||
const chainId = useChainId(VEGA_URL);
|
||||
|
||||
if (
|
||||
!VEGA_URL ||
|
||||
!VEGA_WALLET_URL ||
|
||||
!VEGA_EXPLORER_URL ||
|
||||
!CHROME_EXTENSION_URL ||
|
||||
!MOZILLA_EXTENSION_URL ||
|
||||
!DocsLinks
|
||||
!DocsLinks ||
|
||||
!chainId
|
||||
) {
|
||||
return <AppLoader />;
|
||||
}
|
||||
@@ -72,6 +76,7 @@ export const Bootstrapper = ({ children }: { children: ReactNode }) => {
|
||||
config={{
|
||||
network: VEGA_ENV,
|
||||
vegaUrl: VEGA_URL,
|
||||
chainId,
|
||||
vegaWalletServiceUrl: VEGA_WALLET_URL,
|
||||
links: {
|
||||
explorer: VEGA_EXPLORER_URL,
|
||||
|
||||
@@ -25,12 +25,12 @@ export const ChartContainer = ({ marketId }: { marketId: string }) => {
|
||||
overlays,
|
||||
studies,
|
||||
studySizes,
|
||||
tradingViewStudies,
|
||||
setInterval,
|
||||
setStudies,
|
||||
setStudySizes,
|
||||
setOverlays,
|
||||
setTradingViewStudies,
|
||||
state,
|
||||
setState,
|
||||
} = useChartSettings();
|
||||
|
||||
const pennantChart = (
|
||||
@@ -64,13 +64,13 @@ export const ChartContainer = ({ marketId }: { marketId: string }) => {
|
||||
libraryHash={CHARTING_LIBRARY_HASH}
|
||||
marketId={marketId}
|
||||
interval={toTradingViewResolution(interval)}
|
||||
studies={tradingViewStudies}
|
||||
onIntervalChange={(newInterval) => {
|
||||
setInterval(fromTradingViewResolution(newInterval));
|
||||
}}
|
||||
onAutoSaveNeeded={(data: { studies: string[] }) => {
|
||||
setTradingViewStudies(data.studies);
|
||||
onAutoSaveNeeded={(data) => {
|
||||
setState(data);
|
||||
}}
|
||||
state={state}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ describe('ChartMenu', () => {
|
||||
|
||||
render(<ChartMenu />);
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: 'TradingView' }));
|
||||
await userEvent.click(screen.getByTestId('chartlib-toggle-button'));
|
||||
expect(useChartSettingsStore.getState().chartlib).toEqual('tradingview');
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Vega chart' }));
|
||||
await userEvent.click(screen.getByTestId('chartlib-toggle-button'));
|
||||
expect(useChartSettingsStore.getState().chartlib).toEqual('pennant');
|
||||
});
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ export const ChartMenu = () => {
|
||||
setChartlib(isPennant ? 'tradingview' : 'pennant');
|
||||
}}
|
||||
size="extra-small"
|
||||
testId="chartlib-toggle-button"
|
||||
>
|
||||
{isPennant ? 'TradingView' : t('Vega chart')}
|
||||
</TradingButton>
|
||||
|
||||
@@ -9,6 +9,7 @@ type StudySizes = { [S in Study]?: number };
|
||||
export type Chartlib = 'pennant' | 'tradingview';
|
||||
|
||||
interface StoredSettings {
|
||||
state: object | undefined; // Don't see a better type provided from TradingView type definitions
|
||||
chartlib: Chartlib;
|
||||
// For interval we use the enum from @vegaprotocol/types, this is to make mapping between different
|
||||
// chart types easier and more consistent
|
||||
@@ -17,7 +18,6 @@ interface StoredSettings {
|
||||
overlays: Overlay[];
|
||||
studies: Study[];
|
||||
studySizes: StudySizes;
|
||||
tradingViewStudies: string[];
|
||||
}
|
||||
|
||||
export const STUDY_SIZE = 90;
|
||||
@@ -30,13 +30,13 @@ const STUDY_ORDER: Study[] = [
|
||||
];
|
||||
|
||||
export const DEFAULT_CHART_SETTINGS = {
|
||||
state: undefined,
|
||||
chartlib: 'pennant' as const,
|
||||
interval: Interval.INTERVAL_I15M,
|
||||
type: ChartType.CANDLE,
|
||||
overlays: [Overlay.MOVING_AVERAGE],
|
||||
studies: [Study.MACD, Study.VOLUME],
|
||||
studySizes: {},
|
||||
tradingViewStudies: ['Volume'],
|
||||
};
|
||||
|
||||
export const useChartSettingsStore = create<
|
||||
@@ -47,7 +47,7 @@ export const useChartSettingsStore = create<
|
||||
setStudies: (studies?: Study[]) => void;
|
||||
setStudySizes: (sizes: number[]) => void;
|
||||
setChartlib: (lib: Chartlib) => void;
|
||||
setTradingViewStudies: (studies: string[]) => void;
|
||||
setState: (state: object) => void;
|
||||
}
|
||||
>()(
|
||||
persist(
|
||||
@@ -95,10 +95,8 @@ export const useChartSettingsStore = create<
|
||||
state.chartlib = lib;
|
||||
});
|
||||
},
|
||||
setTradingViewStudies: (studies: string[]) => {
|
||||
set((state) => {
|
||||
state.tradingViewStudies = studies;
|
||||
});
|
||||
setState: (state) => {
|
||||
set({ state });
|
||||
},
|
||||
})),
|
||||
{
|
||||
@@ -147,13 +145,13 @@ export const useChartSettings = () => {
|
||||
overlays,
|
||||
studies,
|
||||
studySizes,
|
||||
tradingViewStudies: settings.tradingViewStudies,
|
||||
setInterval: settings.setInterval,
|
||||
setType: settings.setType,
|
||||
setStudies: settings.setStudies,
|
||||
setOverlays: settings.setOverlays,
|
||||
setStudySizes: settings.setStudySizes,
|
||||
setChartlib: settings.setChartlib,
|
||||
setTradingViewStudies: settings.setTradingViewStudies,
|
||||
state: settings.state,
|
||||
setState: settings.setState,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { GridSettings } from './grid-settings';
|
||||
import '@testing-library/jest-dom';
|
||||
|
||||
describe('GridSettings', () => {
|
||||
it('calls updateGridStore with correct arguments on button click', async () => {
|
||||
const mockUpdateGridStore = jest.fn();
|
||||
const { getByText } = render(
|
||||
<GridSettings updateGridStore={mockUpdateGridStore} />
|
||||
);
|
||||
|
||||
await userEvent.click(getByText('Reset Columns'));
|
||||
|
||||
expect(mockUpdateGridStore).toHaveBeenCalledWith({
|
||||
columnState: undefined,
|
||||
filterModel: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -42,13 +42,9 @@ export const LiquidityHeader = () => {
|
||||
const assetDecimalPlaces = asset?.decimals || 0;
|
||||
const symbol = asset?.symbol;
|
||||
|
||||
const triggeringRatio =
|
||||
market?.liquidityMonitoringParameters.triggeringRatio || '1';
|
||||
|
||||
const { percentage, status } = useCheckLiquidityStatus({
|
||||
suppliedStake: suppliedStake || 0,
|
||||
targetStake: targetStake || 0,
|
||||
triggeringRatio,
|
||||
});
|
||||
|
||||
const feesObject = feesPaidRes?.paidLiquidityFees?.edges?.find(
|
||||
|
||||
@@ -47,9 +47,6 @@ export const MarketLiquiditySupplied = ({
|
||||
]);
|
||||
|
||||
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
|
||||
const triggeringRatio = Number(
|
||||
params.market_liquidity_targetstake_triggering_ratio
|
||||
);
|
||||
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
@@ -94,7 +91,6 @@ export const MarketLiquiditySupplied = ({
|
||||
const { percentage, status } = useCheckLiquidityStatus({
|
||||
suppliedStake: market?.suppliedStake || 0,
|
||||
targetStake: market?.targetStake || 0,
|
||||
triggeringRatio,
|
||||
});
|
||||
|
||||
const showMessage =
|
||||
|
||||
@@ -97,9 +97,9 @@ const MarketData = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-2/5" role="gridcell">
|
||||
<div className="w-2/6" role="gridcell">
|
||||
<h3 className="flex items-baseline">
|
||||
<span className="overflow-hidden text-sm lg:text-base text-ellipsis whitespace-nowrap">
|
||||
<span className="overflow-hidden text-xs md:text-sm lg:text-base text-ellipsis whitespace-nowrap">
|
||||
{market.tradableInstrument.instrument.code}
|
||||
</span>
|
||||
{allProducts && productType && (
|
||||
@@ -113,7 +113,7 @@ const MarketData = ({
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="w-1/5 overflow-hidden text-xs lg:text-sm whitespace-nowrap text-ellipsis"
|
||||
className="w-2/6 overflow-hidden text-xs lg:text-sm whitespace-nowrap text-ellipsis text-right"
|
||||
title={symbol}
|
||||
data-testid="market-selector-price"
|
||||
role="gridcell"
|
||||
@@ -121,14 +121,14 @@ const MarketData = ({
|
||||
{price} {symbol}
|
||||
</div>
|
||||
<div
|
||||
className="w-1/5 overflow-hidden text-xs text-right lg:text-sm whitespace-nowrap text-ellipsis"
|
||||
className="w-2/6 sm:w-1/6 overflow-hidden text-xs lg:text-sm whitespace-nowrap text-ellipsis text-right"
|
||||
title={t('24h vol')}
|
||||
data-testid="market-selector-volume"
|
||||
role="gridcell"
|
||||
>
|
||||
{volume}
|
||||
</div>
|
||||
<div className="flex justify-end w-1/5" role="gridcell">
|
||||
<div className="hidden sm:w-1/6 sm:flex justify-end" role="gridcell">
|
||||
{oneDayCandles && (
|
||||
<Sparkline
|
||||
width={64}
|
||||
|
||||
@@ -64,7 +64,7 @@ export const MarketSelector = ({
|
||||
setFilter((curr) => ({ ...curr, product }));
|
||||
}}
|
||||
/>
|
||||
<div className="text-sm grid grid-cols-[2fr_1fr_1fr] gap-1 ">
|
||||
<div className="text-sm flex sm:grid grid-cols-[2fr_1fr_1fr] gap-1 ">
|
||||
<div className="flex-1">
|
||||
<TradingInput
|
||||
onChange={(e) =>
|
||||
@@ -182,16 +182,16 @@ const MarketList = ({
|
||||
'p-2 mx-2 border-b border-default text-xs text-secondary'
|
||||
)}
|
||||
>
|
||||
<div className="w-2/5" role="columnheader">
|
||||
<div className="w-2/6" role="columnheader">
|
||||
{t('Name')}
|
||||
</div>
|
||||
<div className="w-1/5" role="columnheader">
|
||||
<div className="w-2/6 text-right pr-4" role="columnheader">
|
||||
{t('Price')}
|
||||
</div>
|
||||
<div className="w-1/5 text-right" role="columnheader">
|
||||
<div className="w-2/6 sm:w-1/6 text-right" role="columnheader">
|
||||
{t('24h volume')}
|
||||
</div>
|
||||
<div className="w-1/5" role="columnheader" />
|
||||
<div className="hidden sm:w-1/6" role="columnheader" />
|
||||
</div>
|
||||
<div ref={listRef}>
|
||||
<List
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useParams } from 'react-router-dom';
|
||||
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
||||
import { useState } from 'react';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import classNames from 'classnames';
|
||||
|
||||
/**
|
||||
* This is only rendered for the mobile navigation
|
||||
@@ -30,7 +31,16 @@ export const NavHeader = () => {
|
||||
trigger={
|
||||
<h1 className="flex gap-1 sm:gap-2 md:gap-4 items-center text-default text-lg whitespace-nowrap xl:pr-4 xl:border-r border-default">
|
||||
{data ? data.tradableInstrument.instrument.code : t('Select market')}
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={20} />
|
||||
<span
|
||||
className={classNames(
|
||||
'transition-transform ease-in-out duration-300',
|
||||
{
|
||||
'rotate-180': open,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={20} />
|
||||
</span>
|
||||
</h1>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -162,6 +162,8 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
|
||||
const envNameMapping = useEnvNameMapping();
|
||||
const { VEGA_ENV, VEGA_NETWORKS, GITHUB_FEEDBACK_URL } = useEnvironment();
|
||||
const marketId = useGlobalStore((store) => store.marketId);
|
||||
const GOVERNANCE_LINK = useLinks(DApp.Governance)();
|
||||
const EXPLORER_LINK = useLinks(DApp.Explorer)();
|
||||
|
||||
return (
|
||||
<div className="gap-3 lg:flex lg:h-full">
|
||||
@@ -220,7 +222,7 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
|
||||
</NavbarLink>
|
||||
</NavbarItem>
|
||||
<NavbarItem>
|
||||
<NavbarLinkExternal to={useLinks(DApp.Governance)()}>
|
||||
<NavbarLinkExternal to={GOVERNANCE_LINK}>
|
||||
{t('Governance')}
|
||||
</NavbarLinkExternal>
|
||||
</NavbarItem>
|
||||
@@ -228,6 +230,13 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
|
||||
<NavbarTrigger>{t('Resources')}</NavbarTrigger>
|
||||
<NavbarContent data-testid="navbar-content-resources">
|
||||
<ul className="lg:p-4">
|
||||
{EXPLORER_LINK && (
|
||||
<NavbarSubItem>
|
||||
<NavbarLinkExternal to={EXPLORER_LINK}>
|
||||
{t('Explorer')}
|
||||
</NavbarLinkExternal>
|
||||
</NavbarSubItem>
|
||||
)}
|
||||
{DocsLinks?.NEW_TO_VEGA && (
|
||||
<NavbarSubItem>
|
||||
<NavbarLinkExternal to={DocsLinks?.NEW_TO_VEGA}>
|
||||
|
||||
@@ -98,6 +98,7 @@ describe('ActiveRewards', () => {
|
||||
transferNode={mockTransferNode}
|
||||
currentEpoch={1}
|
||||
kind={mockRecurringTransfer}
|
||||
allMarkets={{}}
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,47 +1,46 @@
|
||||
import {
|
||||
useActiveRewardsQuery,
|
||||
useMarketForRewardsQuery,
|
||||
} from './__generated__/Rewards';
|
||||
import { useActiveRewardsQuery } from './__generated__/Rewards';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
Icon,
|
||||
type IconName,
|
||||
type VegaIconSize,
|
||||
Icon,
|
||||
Intent,
|
||||
Tooltip,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
type VegaIconSize,
|
||||
TradingInput,
|
||||
TinyScroll,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import {
|
||||
type Maybe,
|
||||
type Transfer,
|
||||
type TransferNode,
|
||||
type RecurringTransfer,
|
||||
DistributionStrategyDescriptionMapping,
|
||||
DistributionStrategyMapping,
|
||||
EntityScope,
|
||||
EntityScopeMapping,
|
||||
type Maybe,
|
||||
type Transfer,
|
||||
type TransferNode,
|
||||
TransferStatus,
|
||||
TransferStatusMapping,
|
||||
DispatchMetric,
|
||||
DispatchMetricDescription,
|
||||
DispatchMetricLabels,
|
||||
type RecurringTransfer,
|
||||
EntityScopeLabelMapping,
|
||||
MarketState,
|
||||
} from '@vegaprotocol/types';
|
||||
import { Card } from '../card/card';
|
||||
import { useMemo, useState } from 'react';
|
||||
import {
|
||||
type AssetFieldsFragment,
|
||||
useAssetDataProvider,
|
||||
useAssetsMapProvider,
|
||||
} from '@vegaprotocol/assets';
|
||||
import {
|
||||
type MarketFieldsFragment,
|
||||
useMarketsMapProvider,
|
||||
getAsset,
|
||||
} from '@vegaprotocol/markets';
|
||||
|
||||
export type Filter = {
|
||||
@@ -73,7 +72,7 @@ export const isActiveReward = (node: TransferNode, currentEpoch: number) => {
|
||||
export const applyFilter = (
|
||||
node: TransferNode & {
|
||||
asset?: AssetFieldsFragment | null;
|
||||
marketIds?: (MarketFieldsFragment | null)[];
|
||||
markets?: (MarketFieldsFragment | null)[];
|
||||
},
|
||||
filter: Filter
|
||||
) => {
|
||||
@@ -84,6 +83,7 @@ export const applyFilter = (
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
DispatchMetricLabels[transfer.kind.dispatchStrategy.dispatchMetric]
|
||||
.toLowerCase()
|
||||
@@ -97,7 +97,7 @@ export const applyFilter = (
|
||||
node.asset?.name
|
||||
.toLocaleLowerCase()
|
||||
.includes(filter.searchTerm.toLowerCase()) ||
|
||||
node.marketIds?.some((m) =>
|
||||
node.markets?.some((m) =>
|
||||
m?.tradableInstrument?.instrument?.name
|
||||
.toLocaleLowerCase()
|
||||
.includes(filter.searchTerm.toLowerCase())
|
||||
@@ -123,7 +123,7 @@ export const ActiveRewards = ({ currentEpoch }: { currentEpoch: number }) => {
|
||||
const { data: assets } = useAssetsMapProvider();
|
||||
const { data: markets } = useMarketsMapProvider();
|
||||
|
||||
const transfers = activeRewardsData?.transfersConnection?.edges
|
||||
const enrichedTransfers = activeRewardsData?.transfersConnection?.edges
|
||||
?.map((e) => e?.node as TransferNode)
|
||||
.filter((node) => isActiveReward(node, currentEpoch))
|
||||
.map((node) => {
|
||||
@@ -137,59 +137,58 @@ export const ActiveRewards = ({ currentEpoch }: { currentEpoch: number }) => {
|
||||
node.transfer.kind.dispatchStrategy?.dispatchMetricAssetId || ''
|
||||
];
|
||||
|
||||
const marketIds =
|
||||
const marketsInScope =
|
||||
node.transfer.kind.dispatchStrategy?.marketIdsInScope?.map(
|
||||
(id) => markets && markets[id]
|
||||
);
|
||||
|
||||
return { ...node, asset, marketIds };
|
||||
return { ...node, asset, markets: marketsInScope };
|
||||
});
|
||||
|
||||
if (!transfers || !transfers.length) return null;
|
||||
if (!enrichedTransfers || !enrichedTransfers.length) return null;
|
||||
|
||||
return (
|
||||
<Card title={t('Active rewards')} className="lg:col-span-full">
|
||||
<div className="">
|
||||
{transfers.length > 1 && (
|
||||
<TradingInput
|
||||
onChange={(e) =>
|
||||
setFilter((curr) => ({ ...curr, searchTerm: e.target.value }))
|
||||
{enrichedTransfers.length > 1 && (
|
||||
<TradingInput
|
||||
onChange={(e) =>
|
||||
setFilter((curr) => ({ ...curr, searchTerm: e.target.value }))
|
||||
}
|
||||
value={filter.searchTerm}
|
||||
type="text"
|
||||
placeholder={t(
|
||||
'Search by reward dispatch metric, entity scope or asset name'
|
||||
)}
|
||||
data-testid="search-term"
|
||||
className="mb-4 w-20 mr-2"
|
||||
prependElement={<VegaIcon name={VegaIconNames.SEARCH} />}
|
||||
/>
|
||||
)}
|
||||
<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">
|
||||
{enrichedTransfers
|
||||
.filter((n) => applyFilter(n, filter))
|
||||
.map((node, i) => {
|
||||
const { transfer } = node;
|
||||
if (
|
||||
transfer.kind.__typename !== 'RecurringTransfer' ||
|
||||
!transfer.kind.dispatchStrategy?.dispatchMetric
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
value={filter.searchTerm}
|
||||
type="text"
|
||||
placeholder={t(
|
||||
'Search by reward dispatch metric, entity scope or asset name'
|
||||
)}
|
||||
data-testid="search-term"
|
||||
className="mb-4 w-20"
|
||||
prependElement={<VegaIcon name={VegaIconNames.SEARCH} />}
|
||||
/>
|
||||
)}
|
||||
<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(343px,_1fr))] max-h-[40rem] overflow-auto">
|
||||
{transfers
|
||||
.filter((n) => applyFilter(n, filter))
|
||||
.map((node, i) => {
|
||||
const { transfer } = node;
|
||||
if (
|
||||
transfer.kind.__typename !== 'RecurringTransfer' ||
|
||||
!transfer.kind.dispatchStrategy?.dispatchMetric
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
node && (
|
||||
<ActiveRewardCard
|
||||
key={i}
|
||||
transferNode={node}
|
||||
kind={transfer.kind}
|
||||
currentEpoch={currentEpoch}
|
||||
/>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
node && (
|
||||
<ActiveRewardCard
|
||||
key={i}
|
||||
transferNode={node}
|
||||
kind={transfer.kind}
|
||||
currentEpoch={currentEpoch}
|
||||
allMarkets={markets || {}}
|
||||
/>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</TinyScroll>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -208,14 +207,8 @@ const StatusIndicator = ({
|
||||
switch (status) {
|
||||
case TransferStatus.STATUS_DONE:
|
||||
return { icon: IconNames.TICK_CIRCLE, intent: Intent.Success };
|
||||
case TransferStatus.STATUS_CANCELLED:
|
||||
return { icon: IconNames.MOON, intent: Intent.None };
|
||||
case TransferStatus.STATUS_PENDING:
|
||||
return { icon: IconNames.HELP, intent: Intent.Primary };
|
||||
case TransferStatus.STATUS_REJECTED:
|
||||
return { icon: IconNames.ERROR, intent: Intent.Danger };
|
||||
case TransferStatus.STATUS_STOPPED:
|
||||
return { icon: IconNames.ERROR, intent: Intent.Danger };
|
||||
default:
|
||||
return { icon: IconNames.HELP, intent: Intent.Primary };
|
||||
}
|
||||
@@ -254,49 +247,117 @@ export const ActiveRewardCard = ({
|
||||
transferNode,
|
||||
currentEpoch,
|
||||
kind,
|
||||
allMarkets,
|
||||
}: {
|
||||
transferNode: TransferNode;
|
||||
transferNode: TransferNode & {
|
||||
asset?: AssetFieldsFragment | null;
|
||||
markets?: (MarketFieldsFragment | null)[];
|
||||
};
|
||||
currentEpoch: number;
|
||||
kind: RecurringTransfer;
|
||||
allMarkets?: Record<string, MarketFieldsFragment | null>;
|
||||
}) => {
|
||||
const t = useT();
|
||||
|
||||
const { transfer } = transferNode;
|
||||
const { dispatchStrategy } = kind;
|
||||
const marketIds = dispatchStrategy?.marketIdsInScope;
|
||||
|
||||
const { data: marketNameData } = useMarketForRewardsQuery({
|
||||
variables: {
|
||||
marketId: marketIds ? marketIds[0] : '',
|
||||
},
|
||||
});
|
||||
const marketIdsInScope = dispatchStrategy?.marketIdsInScope;
|
||||
const firstMarketData = transferNode.markets?.[0];
|
||||
|
||||
const marketName = useMemo(() => {
|
||||
if (marketNameData && marketIds && marketIds.length > 1) {
|
||||
return 'Specific markets';
|
||||
} else if (
|
||||
marketNameData &&
|
||||
marketIds &&
|
||||
marketNameData &&
|
||||
marketIds.length === 1
|
||||
const specificMarkets = useMemo(() => {
|
||||
if (
|
||||
!firstMarketData ||
|
||||
!marketIdsInScope ||
|
||||
marketIdsInScope.length === 0
|
||||
) {
|
||||
return marketNameData?.market?.tradableInstrument?.instrument?.name || '';
|
||||
return null;
|
||||
}
|
||||
return '';
|
||||
}, [marketIds, marketNameData]);
|
||||
if (marketIdsInScope.length > 1) {
|
||||
const marketNames =
|
||||
allMarkets &&
|
||||
marketIdsInScope
|
||||
.map((id) => allMarkets[id]?.tradableInstrument?.instrument?.name)
|
||||
.join(', ');
|
||||
|
||||
const { data: dispatchAsset } = useAssetDataProvider(
|
||||
dispatchStrategy?.dispatchMetricAssetId || ''
|
||||
);
|
||||
return (
|
||||
<Tooltip description={marketNames}>
|
||||
<span>Specific markets</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<span>{firstMarketData?.tradableInstrument?.instrument?.name || ''}</span>
|
||||
);
|
||||
}, [firstMarketData, marketIdsInScope, allMarkets]);
|
||||
|
||||
const dispatchAsset = transferNode.asset;
|
||||
|
||||
if (!dispatchStrategy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { gradientClassName, mainClassName } = getGradientClasses(
|
||||
dispatchStrategy.dispatchMetric
|
||||
// Gray out/hide the cards that are related to not trading markets
|
||||
const marketSettled = transferNode.markets?.some(
|
||||
(m) =>
|
||||
m?.state &&
|
||||
[
|
||||
MarketState.STATE_TRADING_TERMINATED,
|
||||
MarketState.STATE_SETTLED,
|
||||
MarketState.STATE_CANCELLED,
|
||||
MarketState.STATE_CLOSED,
|
||||
].includes(m.state)
|
||||
);
|
||||
|
||||
const assetInSettledMarket =
|
||||
allMarkets &&
|
||||
Object.values(allMarkets).some((m: MarketFieldsFragment | null) => {
|
||||
if (m && getAsset(m).id === dispatchStrategy.dispatchMetricAssetId) {
|
||||
return (
|
||||
m?.state &&
|
||||
[
|
||||
MarketState.STATE_TRADING_TERMINATED,
|
||||
MarketState.STATE_SETTLED,
|
||||
MarketState.STATE_CANCELLED,
|
||||
MarketState.STATE_CLOSED,
|
||||
].includes(m.state)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (marketSettled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Gray out the cards that are related to suspended markets
|
||||
const suspended = transferNode.markets?.some(
|
||||
(m) =>
|
||||
m?.state === MarketState.STATE_SUSPENDED ||
|
||||
m?.state === MarketState.STATE_SUSPENDED_VIA_GOVERNANCE
|
||||
);
|
||||
|
||||
const assetInSuspendedMarket =
|
||||
allMarkets &&
|
||||
Object.values(allMarkets).some((m: MarketFieldsFragment | null) => {
|
||||
if (m && getAsset(m).id === dispatchStrategy.dispatchMetricAssetId) {
|
||||
return (
|
||||
m?.state === MarketState.STATE_SUSPENDED ||
|
||||
m?.state === MarketState.STATE_SUSPENDED_VIA_GOVERNANCE
|
||||
);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Gray out the cards that are related to suspended markets
|
||||
const { gradientClassName, mainClassName } =
|
||||
suspended || assetInSuspendedMarket || assetInSettledMarket
|
||||
? {
|
||||
gradientClassName: 'from-vega-cdark-500 to-vega-clight-400',
|
||||
mainClassName: 'from-vega-cdark-400 dark:from-vega-cdark-600 to-20%',
|
||||
}
|
||||
: getGradientClasses(dispatchStrategy.dispatchMetric);
|
||||
|
||||
const entityScope = dispatchStrategy.entityScope;
|
||||
return (
|
||||
<div>
|
||||
@@ -374,8 +435,20 @@ export const ActiveRewardCard = ({
|
||||
|
||||
<span className="border-[0.5px] border-gray-700" />
|
||||
<span>
|
||||
{DispatchMetricLabels[dispatchStrategy.dispatchMetric]}
|
||||
{marketName ? ` • ${marketName}` : ` • ${dispatchAsset?.name}`}
|
||||
{DispatchMetricLabels[dispatchStrategy.dispatchMetric]} •{' '}
|
||||
<Tooltip
|
||||
underline={suspended}
|
||||
description={
|
||||
(suspended || assetInSuspendedMarket) &&
|
||||
(specificMarkets
|
||||
? t('Eligible market(s) currently suspended')
|
||||
: assetInSuspendedMarket
|
||||
? t('Currently no markets eligible for reward')
|
||||
: '')
|
||||
}
|
||||
>
|
||||
<span>{specificMarkets || dispatchAsset?.name}</span>
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
||||
<div className="flex items-center gap-8 flex-wrap">
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest
|
||||
VEGA_VERSION=v0.73.10
|
||||
VEGA_VERSION=v0.74.0-preview.2
|
||||
LOCAL_SERVER=false
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:develop
|
||||
VEGA_VERSION=v0.73.10
|
||||
LOCAL_SERVER=false
|
||||
VEGA_VERSION=v0.74.0-preview.2
|
||||
LOCAL_SERVER=false
|
||||
|
||||
@@ -8,7 +8,7 @@ import docker
|
||||
import http.server
|
||||
import sys
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from playwright.sync_api import Error as PlaywrightError
|
||||
from docker.models.containers import Container
|
||||
from docker.errors import APIError
|
||||
from contextlib import contextmanager
|
||||
@@ -274,3 +274,18 @@ def perps_market(vega, request):
|
||||
if hasattr(request, "param"):
|
||||
kwargs.update(request.param)
|
||||
return setup_perps_market(vega, **kwargs)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def retry_on_http_error(request):
|
||||
retry_count = 3
|
||||
for i in range(retry_count):
|
||||
try:
|
||||
yield
|
||||
return
|
||||
except requests.exceptions.HTTPError:
|
||||
if i < retry_count - 1:
|
||||
print(f"Retrying due to HTTPError (attempt {i+1}/{retry_count})")
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ def setup_simple_market(
|
||||
|
||||
vega.mint(
|
||||
MM_WALLET.name,
|
||||
asset="VOTE",
|
||||
asset=vega.find_asset_id(symbol="VOTE", enabled=True),
|
||||
amount=mint_amount,
|
||||
)
|
||||
|
||||
@@ -207,7 +207,7 @@ def setup_perps_market(
|
||||
|
||||
vega.mint(
|
||||
MM_WALLET.name,
|
||||
asset="VOTE",
|
||||
asset=vega.find_asset_id(symbol="VOTE", enabled=True),
|
||||
amount=mint_amount,
|
||||
)
|
||||
|
||||
|
||||
Generated
+4
-4
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
@@ -1160,8 +1160,8 @@ profile = ["pytest-profiling", "snakeviz"]
|
||||
[package.source]
|
||||
type = "git"
|
||||
url = "https://github.com/vegaprotocol/vega-market-sim.git/"
|
||||
reference = "fix/genesis_panic"
|
||||
resolved_reference = "de30d2d4c7a1b81a830527ca76473e23ef59de12"
|
||||
reference = "HEAD"
|
||||
resolved_reference = "2aed8c94b25d8fa2e376d3b63ca1f9193d28cdfd"
|
||||
|
||||
[[package]]
|
||||
name = "websocket-client"
|
||||
@@ -1342,4 +1342,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.9,<3.11"
|
||||
content-hash = "68ed0de55290a3b929d47eb7f7b031fb7e172261c7bbeb4f554b7c27a4462754"
|
||||
content-hash = "39ce8400de7bf060857447281ef27bd78c9b1d9639da063b051e3ae6e7887a67"
|
||||
|
||||
@@ -9,7 +9,7 @@ packages = [{include = "trading market-sim e2e"}]
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.9,<3.11"
|
||||
psutil = "^5.9.5"
|
||||
vega-sim = {git = "https://github.com/vegaprotocol/vega-market-sim.git/", branch = "fix/genesis_panic"}
|
||||
vega-sim = {git = "https://github.com/vegaprotocol/vega-market-sim.git/"}
|
||||
pytest-playwright = "^0.4.2"
|
||||
docker = "^6.1.3"
|
||||
pytest-xdist = "^3.3.1"
|
||||
|
||||
+36
-23
@@ -14,15 +14,18 @@ market_order = "order-type-Market"
|
||||
tif = "order-tif"
|
||||
expire = "expire"
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega(request):
|
||||
with init_vega(request) as vega:
|
||||
yield vega
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def continuous_market(vega):
|
||||
return setup_continuous_market(vega)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_limit_buy_order_GTT(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
@@ -42,31 +45,26 @@ def test_limit_buy_order_GTT(continuous_market, vega: VegaServiceNull, page: Pag
|
||||
)
|
||||
page.get_by_test_id(place_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
page.get_by_test_id("All").click()
|
||||
# 7002-SORD-017
|
||||
expect(page.get_by_role("row").nth(2)).to_contain_text(
|
||||
"BTC:DAI_2023Futr10+10LimitFilled120.00GTT:"
|
||||
)
|
||||
expect(page.get_by_role("row").nth(5)).to_contain_text("10+10LimitFilled120.00GTT:")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_limit_buy_order(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
|
||||
page.get_by_test_id(order_size).fill("10")
|
||||
page.get_by_test_id(order_price).fill("120")
|
||||
page.get_by_test_id(place_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_fn(2)
|
||||
vega.wait_for_total_catchup()
|
||||
page.get_by_test_id("All").click()
|
||||
# 7002-SORD-017
|
||||
expect(page.get_by_role("row").nth(2)).to_contain_text(
|
||||
"BTC:DAI_2023Futr10+10LimitFilled120.00GTC"
|
||||
)
|
||||
expect(page.get_by_role("row").nth(6)).to_contain_text("10+10LimitFilled120.00GTC")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_limit_sell_order(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
@@ -84,13 +82,11 @@ def test_limit_sell_order(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
)
|
||||
page.get_by_test_id(place_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
page.get_by_test_id("All").click()
|
||||
expect(page.get_by_role("row").nth(2)).to_contain_text(
|
||||
"BTC:DAI_2023Futr10-10LimitFilled100.00GFN"
|
||||
)
|
||||
expect(page.get_by_role("row").nth(7)).to_contain_text("10-10LimitFilled100.00GFN")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_market_sell_order(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
@@ -107,14 +103,12 @@ def test_market_sell_order(continuous_market, vega: VegaServiceNull, page: Page)
|
||||
)
|
||||
page.get_by_test_id(place_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
|
||||
page.get_by_test_id("All").click()
|
||||
expect(page.get_by_role("row").nth(2)).to_contain_text(
|
||||
"BTC:DAI_2023Futr10-10MarketFilled-IOC"
|
||||
)
|
||||
expect(page.get_by_role("row").nth(8)).to_contain_text("10-10MarketFilled-IOC")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_market_buy_order(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
@@ -124,13 +118,32 @@ def test_market_buy_order(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
page.get_by_test_id(tif).select_option("Fill or Kill (FOK)")
|
||||
page.get_by_test_id(place_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
page.get_by_test_id("All").click()
|
||||
# 7002-SORD-010
|
||||
# 0003-WTXN-012
|
||||
# 0003-WTXN-003
|
||||
expect(page.get_by_role("row").nth(2)).to_contain_text(
|
||||
"BTC:DAI_2023Futr10+10MarketFilled-FOK"
|
||||
)
|
||||
expect(page.get_by_role("row").nth(9)).to_contain_text("10+10MarketFilled-FOK")
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_sidebar_should_be_open_after_reload(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
expect(page.get_by_test_id("deal-ticket-form")).to_be_visible()
|
||||
page.get_by_test_id("Order").click()
|
||||
expect(page.get_by_test_id("deal-ticket-form")).not_to_be_visible()
|
||||
page.reload()
|
||||
expect(page.get_by_test_id("deal-ticket-form")).to_be_visible()
|
||||
|
||||
@pytest.mark.skip("We currently can't approve wallet connection through Sim")
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_connect_vega_wallet(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id("order-price").fill("101")
|
||||
page.get_by_test_id("order-connect-wallet").click()
|
||||
expect(page.locator('[role="dialog"]')).to_be_visible()
|
||||
page.get_by_test_id("connector-jsonRpc").click()
|
||||
expect(page.get_by_test_id("wallet-dialog-title")).to_be_visible()
|
||||
# TODO: accept wallet connection and assert wallet is connected.
|
||||
expect(page.get_by_test_id("order-type-Limit")).to_be_checked()
|
||||
expect(page.get_by_test_id("order-price")).to_have_value("101")
|
||||
@@ -1,35 +0,0 @@
|
||||
import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
from conftest import init_vega
|
||||
from fixtures.market import setup_continuous_market
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega(request):
|
||||
with init_vega(request) as vega:
|
||||
yield vega
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def continuous_market(vega):
|
||||
return setup_continuous_market(vega)
|
||||
|
||||
@pytest.mark.skip("We currently can't approve wallet connection through Sim")
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_connect_vega_wallet(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id("order-price").fill("101")
|
||||
page.get_by_test_id("order-connect-wallet").click()
|
||||
expect(page.locator('[role="dialog"]')).to_be_visible()
|
||||
page.get_by_test_id("connector-jsonRpc").click()
|
||||
expect(page.get_by_test_id("wallet-dialog-title")).to_be_visible()
|
||||
# TODO: accept wallet connection and assert wallet is connected.
|
||||
expect(page.get_by_test_id("order-type-Limit")).to_be_checked()
|
||||
expect(page.get_by_test_id("order-price")).to_have_value("101")
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_sidebar_should_be_open_after_reload(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
expect(page.get_by_test_id("deal-ticket-form")).to_be_visible()
|
||||
page.get_by_test_id("Order").click()
|
||||
expect(page.get_by_test_id("deal-ticket-form")).not_to_be_visible()
|
||||
page.reload()
|
||||
expect(page.get_by_test_id("deal-ticket-form")).to_be_visible()
|
||||
@@ -27,7 +27,7 @@ submit_stop_order = "place-order"
|
||||
stop_orders_tab = "Stop orders"
|
||||
row_table = "row"
|
||||
cancel = "cancel"
|
||||
market_name_col = '[col-id="market.tradableInstrument.instrument.code"]'
|
||||
market_name_col = '[data-testid="market-code"]'
|
||||
trigger_col = '[col-id="trigger"]'
|
||||
expiresAt_col = '[col-id="expiresAt"]'
|
||||
size_col = '[col-id="submission.size"]'
|
||||
@@ -41,7 +41,6 @@ close_toast = "toast-close"
|
||||
def create_position(vega: VegaServiceNull, market_id):
|
||||
submit_order(vega, "Key 1", market_id, "SIDE_SELL", 100, 110)
|
||||
submit_order(vega, "Key 1", market_id, "SIDE_BUY", 100, 110)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup
|
||||
|
||||
@@ -78,7 +77,6 @@ def test_submit_stop_order_rejected(continuous_market, vega: VegaServiceNull, pa
|
||||
page.get_by_test_id(trigger_price).fill("103")
|
||||
page.get_by_test_id(order_size).fill("3")
|
||||
page.get_by_test_id(submit_stop_order).click()
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
page.get_by_test_id(close_toast).click()
|
||||
@@ -269,82 +267,6 @@ class TestStopOcoValidation:
|
||||
def continuous_market(self, vega):
|
||||
return setup_continuous_market(vega)
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_stop_market_order_form_validation(self, continuous_market, page: Page):
|
||||
# 7002-SORD-052
|
||||
# 7002-SORD-055
|
||||
# 7002-SORD-056
|
||||
# 7002-SORD-057
|
||||
# 7002-SORD-058
|
||||
# 7002-SORD-064
|
||||
# 7002-SORD-065
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(stop_order_btn).click()
|
||||
page.get_by_test_id(stop_market_order_btn).is_visible()
|
||||
page.get_by_test_id(stop_market_order_btn).click()
|
||||
expect(
|
||||
page.get_by_test_id("sidebar-content").get_by_text("Trigger").first
|
||||
).to_be_visible()
|
||||
expect(page.locator('[for="triggerDirection-risesAbove"]')).to_have_text(
|
||||
"Rises above"
|
||||
)
|
||||
expect(page.locator('[for="triggerDirection-fallsBelow"]')).to_have_text(
|
||||
"Falls below"
|
||||
)
|
||||
page.get_by_test_id(trigger_price).click()
|
||||
expect(page.get_by_test_id(trigger_price)).to_be_empty
|
||||
expect(page.locator('[for="triggerType-price"]')).to_have_text("Price")
|
||||
expect(page.locator('[for="triggerType-trailingPercentOffset"]')).to_have_text(
|
||||
"Trailing Percent Offset"
|
||||
)
|
||||
expect(page.locator('[for="order-size"]')).to_have_text("Size")
|
||||
page.get_by_test_id(order_size).click()
|
||||
expect(page.get_by_test_id(order_size)).to_be_empty
|
||||
expect(page.get_by_test_id(order_price)).not_to_be_visible()
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_stop_limit_order_form_validation(self, continuous_market, page: Page):
|
||||
# 7002-SORD-020
|
||||
# 7002-SORD-021
|
||||
# 7002-SORD-022
|
||||
# 7002-SORD-033
|
||||
# 7002-SORD-034
|
||||
# 7002-SORD-035
|
||||
# 7002-SORD-036
|
||||
# 7002-SORD-037
|
||||
# 7002-SORD-038
|
||||
# 7002-SORD-049
|
||||
# 7002-SORD-050
|
||||
# 7002-SORD-051
|
||||
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(stop_order_btn).click()
|
||||
page.get_by_test_id(stop_limit_order_btn).is_visible()
|
||||
page.get_by_test_id(stop_limit_order_btn).click()
|
||||
expect(
|
||||
page.get_by_test_id("sidebar-content").get_by_text("Trigger").first
|
||||
).to_be_visible()
|
||||
expect(page.locator('[for="triggerDirection-risesAbove"]')).to_have_text(
|
||||
"Rises above"
|
||||
)
|
||||
expect(page.locator('[for="triggerDirection-risesAbove"]')).to_be_checked
|
||||
expect(page.locator('[for="triggerDirection-fallsBelow"]')).to_have_text(
|
||||
"Falls below"
|
||||
)
|
||||
page.get_by_test_id(trigger_price).click()
|
||||
expect(page.get_by_test_id(trigger_price)).to_be_empty
|
||||
expect(page.locator('[for="triggerType-price"]')).to_have_text("Price")
|
||||
expect(page.locator('[for="triggerType-price"]')).to_be_checked
|
||||
expect(page.locator('[for="triggerType-trailingPercentOffset"]')).to_have_text(
|
||||
"Trailing Percent Offset"
|
||||
)
|
||||
expect(page.locator('[for="order-size"]').first).to_have_text("Size")
|
||||
expect(page.locator('[for="order-price"]').last).to_have_text("Price")
|
||||
page.get_by_test_id(order_size).click()
|
||||
expect(page.get_by_test_id(order_size)).to_be_empty
|
||||
page.get_by_test_id(order_price).click()
|
||||
expect(page.get_by_test_id(order_price)).to_be_empty()
|
||||
|
||||
@pytest.mark.skip("core issue")
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_maximum_number_of_active_stop_orders(
|
||||
|
||||
@@ -53,7 +53,7 @@ FEE_BREAKDOWN_TOOLTIP = "fee-breakdown-tooltip"
|
||||
PINNED_ROW_LOCATOR = ".ag-pinned-left-cols-container .ag-row"
|
||||
ROW_LOCATOR = ".ag-center-cols-container .ag-row"
|
||||
# Col-Ids:
|
||||
COL_INSTRUMENT_CODE = '[col-id="market.tradableInstrument.instrument.code"]'
|
||||
COL_INSTRUMENT_CODE = '[data-testid="market-code"]'
|
||||
COL_CODE = '[col-id="code"]'
|
||||
COL_SIZE = '[col-id="size"]'
|
||||
COL_PRICE = '[col-id="price"]'
|
||||
@@ -563,7 +563,6 @@ def test_fills_taker_discount_program(
|
||||
page.goto(f"/#/markets/{market_id}")
|
||||
page.get_by_test_id(FILLS).click()
|
||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||
expect(row.locator(COL_INSTRUMENT_CODE)).to_have_text("BTC:DAI_2023Futr")
|
||||
expect(row.locator(COL_SIZE)).to_have_text(size)
|
||||
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
|
||||
expect(row.locator(COL_PRICE_1)).to_have_text(price_1)
|
||||
@@ -605,7 +604,6 @@ def test_fills_maker_discount_program(
|
||||
change_keys(page, vega_instance, MM_WALLET.name)
|
||||
page.get_by_test_id(FILLS).click()
|
||||
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
|
||||
expect(row.locator(COL_INSTRUMENT_CODE)).to_have_text("BTC:DAI_2023Futr")
|
||||
expect(row.locator(COL_SIZE)).to_have_text(size)
|
||||
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
|
||||
expect(row.locator(COL_PRICE_1)).to_have_text(price_1)
|
||||
@@ -683,4 +681,4 @@ def test_fills_taker_fee_tooltip_discount_program(
|
||||
row.locator(COL_FEE).hover()
|
||||
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
|
||||
f"If the market was activeFees to be paid by the taker; discounts are already applied.Infrastructure fee{infra_fee} tDAILiquidity fee0.00 tDAIMaker fee{maker_fee} tDAITotal fees{total_fee} tDAI"
|
||||
)
|
||||
)
|
||||
@@ -77,7 +77,7 @@ class TestGetStarted:
|
||||
|
||||
vega.mint(
|
||||
MM_WALLET.name,
|
||||
asset="VOTE",
|
||||
asset=vega.find_asset_id(symbol="VOTE", enabled=True),
|
||||
amount=mint_amount,
|
||||
)
|
||||
|
||||
@@ -105,6 +105,8 @@ class TestGetStarted:
|
||||
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
page.reload()
|
||||
|
||||
# Assert step 2 complete
|
||||
expect(page.get_by_test_id("icon-tick")).to_have_count(2)
|
||||
|
||||
@@ -144,29 +146,6 @@ class TestGetStarted:
|
||||
# 0007-FUGS-007
|
||||
expect(page.get_by_test_id("dialog-content").nth(1)).to_be_visible()
|
||||
|
||||
def test_browser_wallet_installed(self, simple_market, page: Page):
|
||||
page.add_init_script("window.vega = {}")
|
||||
page.goto(f"/#/markets/{simple_market}")
|
||||
locator = page.get_by_test_id("connect-vega-wallet")
|
||||
page.wait_for_selector('[data-testid="connect-vega-wallet"]', state="attached")
|
||||
expect(locator).to_be_enabled
|
||||
expect(locator).to_be_visible
|
||||
expect(locator).to_have_text("Connect")
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_get_started_deal_ticket(self,simple_market, page: Page):
|
||||
page.goto(f"/#/markets/{simple_market}")
|
||||
expect(page.get_by_test_id("order-connect-wallet")).to_have_text("Connect wallet")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_browser_wallet_installed_deal_ticket(simple_market, page: Page):
|
||||
page.add_init_script("window.vega = {}")
|
||||
page.goto(f"/#/markets/{simple_market}")
|
||||
# 0007-FUGS-013
|
||||
page.wait_for_selector('[data-testid="sidebar-content"]', state="visible")
|
||||
expect(page.get_by_test_id("get-started-banner")).not_to_be_visible()
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
def test_redirect_default_market(self, continuous_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto("/")
|
||||
@@ -177,11 +156,3 @@ class TestGetStarted:
|
||||
page.get_by_test_id("icon-cross").click()
|
||||
# 0007-FUGS-018
|
||||
expect(page.get_by_test_id("welcome-dialog")).not_to_be_visible()
|
||||
|
||||
class TestBrowseAll:
|
||||
def test_get_started_browse_all(self, simple_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto("/")
|
||||
print(simple_market)
|
||||
page.get_by_test_id("browse-markets-button").click()
|
||||
# 0007-FUGS-005
|
||||
expect(page).to_have_url(f"http://localhost:{vega.console_port}/#/markets/{simple_market}")
|
||||
|
||||
@@ -35,7 +35,6 @@ class TestIcebergOrdersValidations:
|
||||
"Awaiting confirmationPlease wait for your transaction to be confirmedView in block explorer"
|
||||
)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
expect(page.get_by_test_id("toast-content")).to_have_text(
|
||||
@@ -51,7 +50,6 @@ def test_iceberg_open_order(continuous_market, vega: VegaServiceNull, page: Page
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
|
||||
submit_order(vega, "Key 1", continuous_market, "SIDE_SELL", 102, 101, 2, 1)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -84,7 +82,6 @@ def test_iceberg_open_order(continuous_market, vega: VegaServiceNull, page: Page
|
||||
|
||||
submit_order(vega, MM_WALLET2.name, continuous_market, "SIDE_BUY", 103, 101)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
expect(
|
||||
|
||||
@@ -16,35 +16,44 @@ def vega(request):
|
||||
def continuous_market(vega):
|
||||
return setup_continuous_market(vega)
|
||||
|
||||
@pytest.mark.skip("Issue 5581")
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_liquidity_provision_amendment(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
def test_liquidity_provision_amendment(
|
||||
continuous_market, vega: VegaServiceNull, page: Page
|
||||
):
|
||||
# TODO Refactor asserting the grid
|
||||
page.goto(f"/#/liquidity/{continuous_market}")
|
||||
change_keys(page, vega, "market_maker")
|
||||
row = page.get_by_test_id(
|
||||
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
|
||||
expect(row).to_contain_text(
|
||||
"Active"
|
||||
row = (
|
||||
page.get_by_test_id("tab-myLP")
|
||||
.locator(".ag-center-cols-container .ag-row")
|
||||
.first
|
||||
)
|
||||
expect(row).to_contain_text("Active")
|
||||
# 5002-LIQP-006
|
||||
expect(page.get_by_test_id("target-stake")
|
||||
).to_have_text("Target stake5.82757 tDAI")
|
||||
expect(page.get_by_test_id("target-stake")).to_have_text("Target stake5.82757 tDAI")
|
||||
# 5002-LIQP-007
|
||||
expect(page.get_by_test_id("supplied-stake")
|
||||
).to_have_text("Supplied stake10,000.00 tDAI")
|
||||
expect(page.get_by_test_id("supplied-stake")).to_have_text(
|
||||
"Supplied stake10,000.00 tDAI"
|
||||
)
|
||||
# 5002-LIQP-008
|
||||
expect(page.get_by_test_id("liquidity-supplied")
|
||||
).to_have_text("Liquidity supplied 171,598.11%")
|
||||
expect(page.get_by_test_id("liquidity-supplied")).to_have_text(
|
||||
"Liquidity supplied 171,598.11%"
|
||||
)
|
||||
expect(page.get_by_test_id("fees-paid")).to_have_text("Fees paid-")
|
||||
# 5002-LIQP-009
|
||||
expect(page.get_by_test_id("liquidity-market-id")
|
||||
).to_have_text("Market ID" + truncate_middle(continuous_market))
|
||||
expect(page.get_by_test_id("liquidity-learn-more")
|
||||
).to_have_text("Learn moreProviding liquidity")
|
||||
expect(page.get_by_test_id("liquidity-market-id")).to_have_text(
|
||||
"Market ID" + truncate_middle(continuous_market)
|
||||
)
|
||||
expect(page.get_by_test_id("liquidity-learn-more")).to_have_text(
|
||||
"Learn moreProviding liquidity"
|
||||
)
|
||||
# 002-LIQP-010
|
||||
expect(page.get_by_test_id("liquidity-learn-more").get_by_test_id("external-link")
|
||||
).to_have_attribute("href", "https://docs.vega.xyz/testnet/concepts/liquidity/provision")
|
||||
expect(
|
||||
page.get_by_test_id("liquidity-learn-more").get_by_test_id("external-link")
|
||||
).to_have_attribute(
|
||||
"href", "https://docs.vega.xyz/testnet/concepts/liquidity/provision"
|
||||
)
|
||||
|
||||
vega.submit_simple_liquidity(
|
||||
key_name="market_maker",
|
||||
@@ -57,41 +66,50 @@ def test_liquidity_provision_amendment(continuous_market, vega: VegaServiceNull,
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
page.reload()
|
||||
row = page.get_by_test_id(
|
||||
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
|
||||
expect(row).to_contain_text(
|
||||
"Updating next epoch"
|
||||
row = (
|
||||
page.get_by_test_id("tab-myLP")
|
||||
.locator(".ag-center-cols-container .ag-row")
|
||||
.first
|
||||
)
|
||||
expect(row).to_contain_text("Updating next epoch")
|
||||
next_epoch(vega=vega)
|
||||
page.reload()
|
||||
expect(page.get_by_test_id("supplied-stake")).to_have_text(
|
||||
"Supplied stake1.00001 tDAI"
|
||||
)
|
||||
expect(page.get_by_test_id("liquidity-supplied")).to_have_text(
|
||||
"Liquidity supplied 17.16%"
|
||||
)
|
||||
row = (
|
||||
page.get_by_test_id("tab-myLP")
|
||||
.locator(".ag-center-cols-container .ag-row")
|
||||
.first
|
||||
)
|
||||
expect(row).to_contain_text("Active")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_liquidity_provision_cancelled(
|
||||
continuous_market, vega: VegaServiceNull, page: Page
|
||||
):
|
||||
page.goto(f"/#/liquidity/{continuous_market}")
|
||||
change_keys(page, vega, "market_maker")
|
||||
row = (
|
||||
page.get_by_test_id("tab-myLP")
|
||||
.locator(".ag-center-cols-container .ag-row")
|
||||
.first
|
||||
)
|
||||
expect(row).to_contain_text("Active")
|
||||
vega.cancel_liquidity(
|
||||
key_name="market_maker",
|
||||
market_id=continuous_market,
|
||||
)
|
||||
next_epoch(vega=vega)
|
||||
page.reload()
|
||||
expect(page.get_by_test_id("supplied-stake")
|
||||
).to_have_text("Supplied stake1.00001 tDAI")
|
||||
expect(page.get_by_test_id("liquidity-supplied")
|
||||
).to_have_text("Liquidity supplied 17.16%")
|
||||
row = page.get_by_test_id(
|
||||
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
|
||||
expect(row).to_contain_text(
|
||||
"Active"
|
||||
expect(page.get_by_test_id("supplied-stake")).to_have_text(
|
||||
"Supplied stake0.00 tDAI"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skip("Waiting for the ability to cancel LP")
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_liquidity_provision_inactive(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
# TODO Refactor asserting the grid
|
||||
page.goto(f"/#/liquidity/{continuous_market}")
|
||||
change_keys(page, vega, "market_maker")
|
||||
row = page.get_by_test_id(
|
||||
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
|
||||
expect(row).to_contain_text(
|
||||
"Active"
|
||||
expect(page.get_by_test_id("liquidity-supplied")).to_have_text(
|
||||
"Liquidity supplied 0.00%"
|
||||
)
|
||||
vega.submit_simple_liquidity(
|
||||
key_name="market_maker",
|
||||
market_id=continuous_market,
|
||||
commitment_amount=0,
|
||||
fee=0,
|
||||
is_amendment=False,
|
||||
)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
expect(page.locator(".ag-overlay-panel")).to_have_text("No data")
|
||||
|
||||
@@ -5,6 +5,7 @@ from vega_sim.null_service import VegaServiceNull
|
||||
from playwright.sync_api import Page, expect
|
||||
from fixtures.market import setup_continuous_market
|
||||
from conftest import init_vega
|
||||
from actions.utils import next_epoch
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
@@ -21,9 +22,7 @@ def create_settled_market(vega: VegaServiceNull):
|
||||
settlement_price=110,
|
||||
market_id=market_id,
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(10)
|
||||
vega.wait_for_total_catchup()
|
||||
next_epoch(vega=vega)
|
||||
|
||||
|
||||
class TestSettledMarket:
|
||||
@@ -123,9 +122,7 @@ def test_terminated_market_no_settlement_date(page: Page, vega: VegaServiceNull)
|
||||
payload={"trading.terminated": "true"},
|
||||
key_name="FJMKnwfZdd48C8NqvYrG",
|
||||
)
|
||||
vega.forward("60s")
|
||||
vega.wait_fn(10)
|
||||
vega.wait_for_total_catchup()
|
||||
next_epoch(vega=vega)
|
||||
page.goto(f"/#/markets/all")
|
||||
page.get_by_test_id("Closed markets").click()
|
||||
row_selector = page.locator(
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.null_service import VegaServiceNull
|
||||
from actions.vega import submit_order
|
||||
from actions.utils import change_keys
|
||||
from wallet_config import MM_WALLET, MM_WALLET2
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
table_row_selector = (
|
||||
'[data-testid="tab-open-markets"] .ag-center-cols-container .ag-row'
|
||||
)
|
||||
trading_mode_col = '[col-id="tradingMode"]'
|
||||
state_col = '[col-id="state"]'
|
||||
item_value = "item-value"
|
||||
price_monitoring_bounds_row = "key-value-table-row"
|
||||
market_trading_mode = "market-trading-mode"
|
||||
market_state = "market-state"
|
||||
liquidity_supplied = "liquidity-supplied"
|
||||
item_value = "item-value"
|
||||
price_monitoring_bounds_row = "key-value-table-row"
|
||||
market_trading_mode = "market-trading-mode"
|
||||
market_state = "market-state"
|
||||
liquidity_supplied = "liquidity-supplied"
|
||||
|
||||
initial_commitment: float = 100
|
||||
initial_price: float = 1
|
||||
initial_volume: float = 1
|
||||
initial_spread: float = 0.1
|
||||
market_name = "BTC:DAI_2023"
|
||||
|
||||
@pytest.mark.skip("tbd")
|
||||
@pytest.mark.usefixtures("risk_accepted", "auth")
|
||||
def test_price_monitoring(simple_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto(f"/#/markets/all")
|
||||
expect(page.locator(table_row_selector).locator(trading_mode_col)).to_have_text(
|
||||
"Opening auction"
|
||||
)
|
||||
expect(page.locator(table_row_selector).locator('[col-id="state"]')).to_have_text(
|
||||
"Pending"
|
||||
)
|
||||
result = page.get_by_text(market_name)
|
||||
result.first.click()
|
||||
page.get_by_test_id(market_trading_mode).get_by_text("Opening auction").hover()
|
||||
expect(page.get_by_test_id("opening-auction-sub-status").first).to_have_text(
|
||||
"Opening auction: Not enough liquidity to open"
|
||||
)
|
||||
logger.info(page.get_by_test_id("opening-auction-sub-status").inner_text)
|
||||
vega.submit_liquidity(
|
||||
key_name=MM_WALLET.name,
|
||||
market_id=simple_market,
|
||||
commitment_amount=initial_commitment,
|
||||
fee=0.002,
|
||||
is_amendment=False,
|
||||
)
|
||||
|
||||
vega.submit_order(
|
||||
market_id=simple_market,
|
||||
trading_key=MM_WALLET.name,
|
||||
side="SIDE_BUY",
|
||||
order_type="TYPE_LIMIT",
|
||||
price=initial_price - 0.0005,
|
||||
wait=False,
|
||||
time_in_force="TIME_IN_FORCE_GTC",
|
||||
volume=99,
|
||||
)
|
||||
vega.submit_order(
|
||||
market_id=simple_market,
|
||||
trading_key=MM_WALLET.name,
|
||||
side="SIDE_SELL",
|
||||
order_type="TYPE_LIMIT",
|
||||
price=initial_price + 0.0005,
|
||||
wait=False,
|
||||
time_in_force="TIME_IN_FORCE_GTC",
|
||||
volume=99,
|
||||
)
|
||||
# 6002-MDET-009
|
||||
expect(
|
||||
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
|
||||
).to_have_text("0.00 (0.00%)")
|
||||
|
||||
# add orders to provide liquidity
|
||||
submit_order(
|
||||
vega, MM_WALLET.name, simple_market, "SIDE_BUY", initial_volume, initial_price
|
||||
)
|
||||
submit_order(
|
||||
vega, MM_WALLET.name, simple_market, "SIDE_SELL", initial_volume, initial_price
|
||||
)
|
||||
submit_order(
|
||||
vega,
|
||||
MM_WALLET.name,
|
||||
simple_market,
|
||||
"SIDE_BUY",
|
||||
initial_volume,
|
||||
initial_price + initial_spread / 2,
|
||||
)
|
||||
submit_order(
|
||||
vega,
|
||||
MM_WALLET.name,
|
||||
simple_market,
|
||||
"SIDE_SELL",
|
||||
initial_volume,
|
||||
initial_price + initial_spread / 2,
|
||||
)
|
||||
submit_order(
|
||||
vega, MM_WALLET2.name, simple_market, "SIDE_SELL", initial_volume, initial_price
|
||||
)
|
||||
expect(
|
||||
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
|
||||
).to_have_text("100.00 (>100%)")
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(10)
|
||||
vega.wait_for_total_catchup()
|
||||
expect(
|
||||
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
|
||||
).to_have_text("50.00 (>100%)")
|
||||
|
||||
page.goto(f"/#/markets/all")
|
||||
# temporary skip
|
||||
# expect(page.locator(table_row_selector).locator(trading_mode_col)).to_have_text(
|
||||
# "Continuous"
|
||||
# )
|
||||
|
||||
# commented out because we have an issue #4233
|
||||
# expect(page.locator(row_selector).locator(state_col)
|
||||
# ).to_have_text("Pending")
|
||||
|
||||
page.goto(f"/#/markets/all")
|
||||
result = page.get_by_text(market_name)
|
||||
result.first.click()
|
||||
|
||||
page.get_by_test_id("Info").click()
|
||||
page.get_by_test_id("accordion-title").get_by_text(
|
||||
"Price monitoring bounds 1"
|
||||
).click()
|
||||
expect(
|
||||
page.get_by_test_id(price_monitoring_bounds_row).first.get_by_text(
|
||||
"1.32217 BTC"
|
||||
)
|
||||
).to_be_visible()
|
||||
expect(
|
||||
page.get_by_test_id(price_monitoring_bounds_row).last.get_by_text("0.79245 BTC")
|
||||
).to_be_visible()
|
||||
|
||||
# add orders that change the price so that it goes beyond the limits of price monitoring
|
||||
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 100, 110)
|
||||
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 100, 90)
|
||||
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 100, 105)
|
||||
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 100, 95)
|
||||
|
||||
# add order at the current price so that it is possible to change the status to price monitoring
|
||||
to_cancel = submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 1, 105)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
expect(
|
||||
page.get_by_test_id(price_monitoring_bounds_row).first.get_by_text(
|
||||
"135.44204 BTC"
|
||||
)
|
||||
).to_be_visible()
|
||||
expect(
|
||||
page.get_by_test_id(price_monitoring_bounds_row).last.get_by_text(
|
||||
"81.17758 BTC"
|
||||
)
|
||||
).to_be_visible()
|
||||
expect(
|
||||
page.get_by_test_id(market_trading_mode).get_by_test_id(item_value)
|
||||
).to_have_text("Monitoring auction - price")
|
||||
expect(page.get_by_test_id(market_state).get_by_test_id(item_value)).to_have_text(
|
||||
"Suspended"
|
||||
)
|
||||
expect(
|
||||
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
|
||||
).to_have_text("50.00 (8.78%)")
|
||||
|
||||
# cancel order to increase liquidity
|
||||
vega.cancel_order(MM_WALLET2.name, simple_market, to_cancel)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
expect(page.get_by_text(market_name).first).to_be_attached()
|
||||
expect(
|
||||
page.get_by_test_id(market_trading_mode).get_by_test_id(item_value)
|
||||
).to_have_text("Continuous")
|
||||
expect(page.get_by_test_id(market_state).get_by_test_id(item_value)).to_have_text(
|
||||
"Active"
|
||||
)
|
||||
# commented out because we have an issue #4233
|
||||
# expect(page.get_by_text("Opening auction")).to_be_hidden()
|
||||
|
||||
# 6002-MDET-009
|
||||
expect(
|
||||
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
|
||||
).to_have_text("50.00 (>100%)")
|
||||
|
||||
|
||||
COL_ID_FEE = ".ag-center-cols-container [col-id='fee'] .ag-cell-value"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted", "auth")
|
||||
def test_auction_uncross_fees(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id("Fills").click()
|
||||
expect(page.locator(COL_ID_FEE)).to_have_text("0.00 tDAI")
|
||||
# tbd - tooltip is not visible without this wait
|
||||
page.wait_for_timeout(1000)
|
||||
page.get_by_role("gridcell", name="0.00 tDAI").nth(0).hover()
|
||||
expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text(
|
||||
"If the market was suspendedDuring auction, half the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI"
|
||||
)
|
||||
change_keys(page, vega, "market_maker")
|
||||
expect(page.locator(COL_ID_FEE)).to_have_text("0.00 tDAI")
|
||||
# tbd - tooltip is not visible without this wait
|
||||
page.wait_for_timeout(1000)
|
||||
page.get_by_role("gridcell", name="0.00 tDAI").nth(0).hover()
|
||||
expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text(
|
||||
"If the market was suspendedDuring auction, half the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI"
|
||||
)
|
||||
@@ -25,65 +25,3 @@ def test_market_selector(continuous_market, page: Page):
|
||||
expect(btc_market.locator("span.rounded-md.leading-none")).to_be_visible()
|
||||
expect(btc_market.locator("span.rounded-md.leading-none")).to_have_text("Futr")
|
||||
expect(btc_market.locator('[data-testid="sparkline-svg"]')).not_to_be_visible
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("simple_market", "auth", "risk_accepted")
|
||||
@pytest.mark.parametrize(
|
||||
"simple_market",
|
||||
[
|
||||
{
|
||||
"custom_market_name": "APPL.MF21",
|
||||
"custom_asset_name": "tUSDC",
|
||||
"custom_asset_symbol": "tUSDC",
|
||||
}
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_market_selector_filter(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id("header-title").click()
|
||||
# 6001-MARK-027
|
||||
page.get_by_test_id("product-Spot").click()
|
||||
expect(page.get_by_test_id("market-selector-list")).to_contain_text(
|
||||
"Spot markets coming soon."
|
||||
)
|
||||
page.get_by_test_id("product-Perpetual").click()
|
||||
expect(page.get_by_test_id("market-selector-list")).to_contain_text(
|
||||
"No perpetual markets."
|
||||
)
|
||||
page.get_by_test_id("product-Future").click()
|
||||
expect(page.locator('[data-testid="market-selector-list"] a')).to_have_count(2)
|
||||
|
||||
# 6001-MARK-029
|
||||
page.get_by_test_id("search-term").fill("btc")
|
||||
expect(page.locator('[data-testid="market-selector-list"] a')).to_have_count(1)
|
||||
# tbd - 5465
|
||||
expect(page.locator('[data-testid="market-selector-list"] a').nth(0)).to_contain_text(
|
||||
"BTC:DAI_2023107.50 tDAI"
|
||||
)
|
||||
|
||||
page.get_by_test_id("search-term").clear()
|
||||
expect(page.locator('[data-testid="market-selector-list"] a')).to_have_count(2)
|
||||
|
||||
# 6001-MARK-030
|
||||
# 6001-MARK-031
|
||||
# 6001-MARK-032
|
||||
# 6001-MARK-033
|
||||
page.get_by_test_id("sort-trigger").click()
|
||||
|
||||
expect(page.get_by_test_id("sort-item-Gained")).to_have_text("Top gaining")
|
||||
expect(page.get_by_test_id("sort-item-Gained")).to_be_visible()
|
||||
expect(page.get_by_test_id("sort-item-Lost")).to_have_text("Top losing")
|
||||
expect(page.get_by_test_id("sort-item-Lost")).to_be_visible()
|
||||
expect(page.get_by_test_id("sort-item-New")).to_have_text("New markets")
|
||||
expect(page.get_by_test_id("sort-item-New")).to_be_visible()
|
||||
|
||||
# 6001-MARK-028
|
||||
page.get_by_test_id("sort-trigger").click(force=True)
|
||||
page.get_by_test_id("asset-trigger").click()
|
||||
page.get_by_role("menuitemcheckbox").nth(0).get_by_text("tDAI").click()
|
||||
expect(page.locator('[data-testid="market-selector-list"] a')).to_have_count(1)
|
||||
# tbd - 5465
|
||||
expect(page.locator('[data-testid="market-selector-list"] a').nth(0)).to_contain_text(
|
||||
"BTC:DAI_2023107.50 tDAI"
|
||||
)
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
|
||||
from conftest import init_page, init_vega, risk_accepted_setup
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega(request):
|
||||
with init_vega(request) as vega:
|
||||
yield vega
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def page(vega, browser, request):
|
||||
with init_page(vega, browser, request) as page:
|
||||
risk_accepted_setup(page)
|
||||
page.goto("/#/markets/all")
|
||||
yield page
|
||||
|
||||
|
||||
def test_no_open_markets(page: Page):
|
||||
# 6001-MARK-034
|
||||
page.get_by_test_id("Open markets").click()
|
||||
expect(page.locator(".ag-overlay-wrapper")).to_have_text("No markets")
|
||||
|
||||
|
||||
def test_no_closed_markets(page: Page):
|
||||
page.get_by_test_id("Closed markets").click()
|
||||
expect(page.locator(".ag-overlay-wrapper")).to_have_text("No markets")
|
||||
|
||||
|
||||
def test_no_proposed_markets(page: Page):
|
||||
# 6001-MARK-061
|
||||
page.get_by_test_id("Proposed markets").click()
|
||||
expect(page.locator(".ag-overlay-wrapper")).to_have_text("No proposed markets")
|
||||
@@ -56,9 +56,6 @@ def test_renders_markets_correctly(proposed_market, page: Page):
|
||||
page.goto(f"/#/markets/all")
|
||||
page.click('[data-testid="Proposed markets"]')
|
||||
row = page.locator(row_selector)
|
||||
# 6001-MARK-049
|
||||
expect(row.locator(col_market_id)).to_have_text("BTC:DAI_2023")
|
||||
|
||||
# 6001-MARK-051
|
||||
expect(row.locator('[col-id="asset"]')).to_have_text("tDAI")
|
||||
|
||||
|
||||
@@ -4,9 +4,14 @@ from vega_sim.null_service import VegaServiceNull
|
||||
from actions.vega import submit_order
|
||||
from fixtures.market import setup_simple_market
|
||||
from conftest import init_vega
|
||||
from actions.utils import wait_for_toast_confirmation
|
||||
from actions.utils import wait_for_toast_confirmation, change_keys
|
||||
from wallet_config import MM_WALLET, MM_WALLET2
|
||||
|
||||
market_trading_mode = "market-trading-mode"
|
||||
market_state = "market-state"
|
||||
item_value = "item-value"
|
||||
|
||||
COL_ID_FEE = ".ag-center-cols-container [col-id='fee'] .ag-cell-value"
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega(request):
|
||||
@@ -64,18 +69,16 @@ def setup_market_monitoring_auction(vega: VegaServiceNull, simple_market):
|
||||
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 1, 1 + 0.1 / 2)
|
||||
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_SELL", 1, 1)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
# add orders that change the price so that it goes beyond the limits of price monitoring
|
||||
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 100, 110)
|
||||
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 100, 90)
|
||||
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 100, 105)
|
||||
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 100, 95)
|
||||
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 1, 105)
|
||||
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 100, 300)
|
||||
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 100, 290)
|
||||
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 100, 305)
|
||||
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 100, 295)
|
||||
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 1, 305)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -91,7 +94,6 @@ def test_market_monitoring_auction_price_volatility_limit_order(
|
||||
page.get_by_test_id("order-price").type("110")
|
||||
page.get_by_test_id("order-tif").select_option("Fill or Kill (FOK)")
|
||||
page.get_by_test_id("place-order").click()
|
||||
|
||||
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_have_text(
|
||||
"This market is in auction due to high price volatility. Until the auction ends, you can only place GFA, GTT, or GTC limit orders."
|
||||
)
|
||||
@@ -109,12 +111,11 @@ def test_market_monitoring_auction_price_volatility_limit_order(
|
||||
page.get_by_test_id("place-order").click()
|
||||
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
page.get_by_test_id("All").click()
|
||||
expect(page.get_by_role("row").nth(2)).to_contain_text(
|
||||
"BTC:DAI_2023Futr0+1LimitActive110.00GTC"
|
||||
expect(page.get_by_role("row").nth(4)).to_contain_text(
|
||||
"0+1LimitActive110.00GTC"
|
||||
)
|
||||
|
||||
|
||||
@@ -128,7 +129,6 @@ def test_market_monitoring_auction_price_volatility_market_order(
|
||||
page.get_by_test_id("order-size").type("1")
|
||||
# 7002-SORD-060
|
||||
page.get_by_test_id("place-order").click()
|
||||
|
||||
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_have_text(
|
||||
"This market is in auction due to high price volatility. Until the auction ends, you can only place GFA, GTT, or GTC limit orders."
|
||||
)
|
||||
@@ -138,3 +138,29 @@ def test_market_monitoring_auction_price_volatility_market_order(
|
||||
"This market is in auction due to high price volatility. Only limit orders are permitted when market is in auction."
|
||||
)
|
||||
expect(page.get_by_test_id("deal-ticket-error-message-type")).to_be_visible()
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted", "auth", "setup_market_monitoring_auction")
|
||||
def test_market_price_volatility(
|
||||
page: Page, simple_market, vega: VegaServiceNull
|
||||
):
|
||||
page.goto(f"/#/markets/{simple_market}")
|
||||
expect(
|
||||
page.get_by_test_id(market_trading_mode).get_by_test_id(item_value)
|
||||
).to_have_text("Monitoring auction - price")
|
||||
expect(page.get_by_test_id(market_state).get_by_test_id(item_value)).to_have_text(
|
||||
"Suspended"
|
||||
)
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted", "auth", "setup_market_monitoring_auction")
|
||||
def test_auction_uncross_fees(simple_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto(f"/#/markets/{simple_market}")
|
||||
change_keys(page, vega, "market_maker")
|
||||
page.get_by_test_id("Fills").click()
|
||||
row = page.locator('[row-index="3"]').nth(1)
|
||||
expect(row.locator('[col-id="fee"]')).to_have_text("0.00 tDAI")
|
||||
# tbd - tooltip is not visible without this wait
|
||||
page.wait_for_timeout(1000)
|
||||
row.locator('[col-id="fee"]').hover()
|
||||
expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text(
|
||||
"If the market was suspendedDuring auction, half the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI"
|
||||
)
|
||||
@@ -73,9 +73,6 @@ def test_market_lifecycle(proposed_market, vega: VegaServiceNull, page: Page):
|
||||
)
|
||||
|
||||
# "wait" for market to be approved and enacted
|
||||
vega.forward("60s")
|
||||
vega.wait_fn(10)
|
||||
vega.wait_for_total_catchup()
|
||||
next_epoch(vega=vega)
|
||||
# check that market is in pending state
|
||||
expect(trading_mode).to_have_text("Opening auction")
|
||||
@@ -118,8 +115,7 @@ def test_market_lifecycle(proposed_market, vega: VegaServiceNull, page: Page):
|
||||
submit_order(vega, MM_WALLET.name, market_id, "SIDE_SELL", 1, 100)
|
||||
submit_order(vega, MM_WALLET2.name, market_id, "SIDE_BUY", 1, 100)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_fn(2)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
# check market state is now active and trading mode is continuous
|
||||
@@ -139,9 +135,7 @@ def test_market_lifecycle(proposed_market, vega: VegaServiceNull, page: Page):
|
||||
.get_by_test_id(f"update-state-banner-{market_id}")
|
||||
).to_be_visible()
|
||||
|
||||
vega.forward("60s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
next_epoch(vega=vega)
|
||||
|
||||
expect(
|
||||
page.get_by_test_id("market-banner")
|
||||
@@ -155,9 +149,7 @@ def test_market_lifecycle(proposed_market, vega: VegaServiceNull, page: Page):
|
||||
forward_time_to_enactment = False
|
||||
)
|
||||
|
||||
vega.forward("60s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
next_epoch(vega=vega)
|
||||
|
||||
expect(page.get_by_test_id("market-banner")).not_to_be_visible()
|
||||
|
||||
@@ -170,11 +162,9 @@ def test_market_lifecycle(proposed_market, vega: VegaServiceNull, page: Page):
|
||||
payload={"trading.terminated": "true"},
|
||||
key_name=GOVERNANCE_WALLET.name,
|
||||
)
|
||||
vega.forward("60s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
next_epoch(vega=vega)
|
||||
|
||||
# market state should be changed to "Trading Terminated" because of the invalid oracle
|
||||
# market state should be changed to "No trading" because of the invalid oracle
|
||||
expect(trading_mode).to_have_text("No trading")
|
||||
expect(market_state).to_have_text("Trading Terminated")
|
||||
|
||||
@@ -184,9 +174,7 @@ def test_market_lifecycle(proposed_market, vega: VegaServiceNull, page: Page):
|
||||
settlement_price=100,
|
||||
market_id=market_id,
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
next_epoch(vega=vega)
|
||||
|
||||
# check market state is now settled
|
||||
expect(trading_mode).to_have_text("No trading")
|
||||
|
||||
@@ -44,7 +44,7 @@ def verify_order_value(
|
||||
actual_text = element.text_content()
|
||||
|
||||
if actual_text is None:
|
||||
raise Exception(f"no text found for test_id {test_id}")
|
||||
raise Exception(f"no text found for test_id {test_id}")
|
||||
|
||||
assert re.match(
|
||||
expected_text, actual_text
|
||||
|
||||
@@ -65,7 +65,6 @@ def test_limit_order_trade_open_order(
|
||||
expect(orderbook_trade).to_be_visible()
|
||||
|
||||
expected_open_order = [
|
||||
"BTC:DAI_2023",
|
||||
"+1",
|
||||
"Limit",
|
||||
"Active",
|
||||
@@ -87,9 +86,6 @@ def test_limit_order_trade_open_position(continuous_market, page: Page):
|
||||
secondary_id = "stack-cell-secondary"
|
||||
|
||||
position = {
|
||||
"market_code": "BTC:DAI_2023",
|
||||
"settlement_asset": "tDAI",
|
||||
"product_type": "Futr",
|
||||
"size": "+1",
|
||||
"notional": "107.50",
|
||||
"average_entry_price": "107.50",
|
||||
@@ -107,12 +103,6 @@ def test_limit_order_trade_open_position(continuous_market, page: Page):
|
||||
# 7004-POSI-001
|
||||
# 7004-POSI-002
|
||||
|
||||
market = table.locator("[col-id='marketCode']")
|
||||
expect(market.get_by_test_id(primary_id)).to_have_text(position["market_code"])
|
||||
expect(market.get_by_test_id(secondary_id)).to_have_text(
|
||||
position["settlement_asset"] + position["product_type"]
|
||||
)
|
||||
|
||||
size_and_notional = table.locator("[col-id='openVolume']")
|
||||
expect(size_and_notional.get_by_test_id(primary_id)).to_have_text(position["size"])
|
||||
expect(size_and_notional.get_by_test_id(secondary_id)).to_have_text(
|
||||
@@ -154,5 +144,4 @@ def test_limit_order_trade_order_trade_away(continuous_market, page: Page):
|
||||
page.get_by_test_id("Orderbook").click()
|
||||
price_element = page.get_by_test_id("price-11000000").nth(1)
|
||||
# 6003-ORDB-010
|
||||
print(price_element)
|
||||
expect(price_element).to_be_hidden()
|
||||
|
||||
@@ -257,46 +257,63 @@ def test_order_sorted(page: Page):
|
||||
|
||||
def test_order_status_active(page: Page):
|
||||
# 7002-SORD-041
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
"market-2Futr" + "0" + "-10" + "Limit" + "Active" + "150.00" + "GTC"
|
||||
expect(page.locator('[row-index="2"]').first).to_contain_text(
|
||||
"market-2Futr"
|
||||
)
|
||||
expect(page.locator('[row-index="2"]').nth(1)).to_contain_text(
|
||||
"0" + "-10" + "Limit" + "Active" + "150.00" + "GTC"
|
||||
)
|
||||
|
||||
|
||||
def test_status_expired(page: Page):
|
||||
# 7002-SORD-042
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
"market-3Futr" + "0" + "-10" + "Limit" + "Expired" + "120.00" + "GTT:"
|
||||
expect(page.locator('[row-index="7"]').first).to_contain_text(
|
||||
"market-3Futr"
|
||||
)
|
||||
expect(page.locator('[row-index="7"]').nth(1)).to_contain_text(
|
||||
"0" + "-10" + "Limit" + "Expired" + "120.00" + "GTT:"
|
||||
)
|
||||
|
||||
|
||||
def test_order_status_Stopped(page: Page):
|
||||
# 7002-SORD-044
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
"market-1Futr" + "0" + "-100" + "Limit" + "Stopped" + "130.00" + "IOC"
|
||||
expect(page.locator('[row-index="12"]').first).to_contain_text(
|
||||
"market-1Futr"
|
||||
)
|
||||
expect(page.locator('[row-index="12"]').nth(1)).to_contain_text(
|
||||
"0" + "-100" + "Limit" + "Stopped" + "130.00" + "IOC"
|
||||
)
|
||||
|
||||
|
||||
def test_order_status_partially_filled(page: Page):
|
||||
# 7002-SORD-045
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
"market-2Futr" + "99" + "+100" + "Limit" + "Partially Filled" + "104.00" + "IOC"
|
||||
expect(page.locator('[row-index="8"]').first).to_contain_text(
|
||||
"market-2Futr"
|
||||
)
|
||||
expect(page.locator('[row-index="8"]').nth(1)).to_contain_text(
|
||||
"99" + "+100" + "Limit" + "Partially Filled" + "104.00" + "IOC"
|
||||
)
|
||||
|
||||
|
||||
def test_order_status_filled(page: Page):
|
||||
# 7002-SORD-046
|
||||
# 7003-MORD-020
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
"market-1Futr" + "100" + "-100" + "Limit" + "Filled" + "88.00" + "GTC"
|
||||
expect(page.locator('[row-index="11"]').first).to_contain_text(
|
||||
"market-1Futr"
|
||||
)
|
||||
expect(page.locator('[row-index="11"]').nth(1)).to_contain_text(
|
||||
"100" + "-100" + "Limit" + "Filled" + "88.00" + "GTC"
|
||||
)
|
||||
|
||||
|
||||
def test_order_status_rejected(page: Page):
|
||||
# 7002-SORD-047
|
||||
# 7003-MORD-018
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
expect(page.locator('[row-index="9"]').first).to_contain_text(
|
||||
"market-1Futr"
|
||||
+ "0"
|
||||
)
|
||||
expect(page.locator('[row-index="9"]').nth(1)).to_contain_text(
|
||||
"0"
|
||||
+ "-10,000,000,000"
|
||||
+ "Limit"
|
||||
+ "Rejected: Margin check failed"
|
||||
@@ -308,9 +325,11 @@ def test_order_status_rejected(page: Page):
|
||||
def test_order_status_parked(page: Page):
|
||||
# 7002-SORD-048
|
||||
# 7003-MORD-016
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
expect(page.locator('[row-index="3"]').first).to_contain_text(
|
||||
"market-5Futr"
|
||||
+ "0"
|
||||
)
|
||||
expect(page.locator('[row-index="3"]').nth(1)).to_contain_text(
|
||||
"0"
|
||||
+ "-60"
|
||||
+ "Ask + 15.00 Peg limit"
|
||||
+ "Parked"
|
||||
@@ -321,9 +340,11 @@ def test_order_status_parked(page: Page):
|
||||
|
||||
def test_order_status_pegged_ask(page: Page):
|
||||
# 7003-MORD-016
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
expect(page.locator('[row-index="4"]').first).to_contain_text(
|
||||
"market-4Futr"
|
||||
+ "0"
|
||||
)
|
||||
expect(page.locator('[row-index="4"]').nth(1)).to_contain_text(
|
||||
"0"
|
||||
+ "-60"
|
||||
+ "Ask + 15.00 Peg limit"
|
||||
+ "Active"
|
||||
@@ -334,9 +355,11 @@ def test_order_status_pegged_ask(page: Page):
|
||||
|
||||
def test_order_status_pegged_bid(page: Page):
|
||||
# 7003-MORD-016
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
expect(page.locator('[row-index="5"]').first).to_contain_text(
|
||||
"market-4Futr"
|
||||
+ "0"
|
||||
)
|
||||
expect(page.locator('[row-index="5"]').nth(1)).to_contain_text(
|
||||
"0"
|
||||
+ "+40"
|
||||
+ "Bid - 10.00 Peg limit"
|
||||
+ "Active"
|
||||
@@ -347,9 +370,11 @@ def test_order_status_pegged_bid(page: Page):
|
||||
|
||||
def test_order_status_pegged_mid(page: Page):
|
||||
# 7003-MORD-016
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
expect(page.locator('[row-index="6"]').first).to_contain_text(
|
||||
"market-4Futr"
|
||||
+ "0"
|
||||
)
|
||||
expect(page.locator('[row-index="6"]').nth(1)).to_contain_text(
|
||||
"0"
|
||||
+ "+20"
|
||||
+ "Mid - 5.00 Peg limit"
|
||||
+ "Active"
|
||||
@@ -372,9 +397,11 @@ def test_order_amend_order(vega: VegaServiceNull, page: Page):
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
"market-2Futr" + "0" + "-15" + "Limit" + "Active" + "170.00" + "GTC"
|
||||
expect(page.locator('[row-index="1"]').first).to_contain_text(
|
||||
"market-2Futr"
|
||||
)
|
||||
expect(page.locator('[row-index="1"]').nth(1)).to_contain_text(
|
||||
"0" + "-15" + "Limit" + "Active" + "170.00" + "GTC"
|
||||
)
|
||||
|
||||
|
||||
@@ -389,9 +416,11 @@ def test_order_cancel_single_order(vega: VegaServiceNull, page: Page):
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
expect(page.get_by_test_id(order_tab)).to_contain_text(
|
||||
"market-3Futr" + "0" + "+10" + "Limit" + "Cancelled" + "60.00" + "GTC"
|
||||
expect(page.locator('[row-index="0"]').first).to_contain_text(
|
||||
"market-3Futr"
|
||||
)
|
||||
expect(page.locator('[row-index="0"]').nth(1)).to_contain_text(
|
||||
"0" + "+10" + "Limit" + "Cancelled" + "60.00" + "GTC"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -106,7 +106,6 @@ def test_orderbook_grid_content(setup_market, page: Page):
|
||||
matching_order[1],
|
||||
)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -233,7 +232,6 @@ def test_orderbook_price_movement(setup_market, page: Page):
|
||||
matching_order_1[1],
|
||||
)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -254,7 +252,6 @@ def test_orderbook_price_movement(setup_market, page: Page):
|
||||
matching_order_2[1],
|
||||
)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ class TestPerpetuals:
|
||||
settlement_price=110,
|
||||
market_id=perps_market,
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
submit_multiple_orders(
|
||||
@@ -48,8 +47,7 @@ class TestPerpetuals:
|
||||
settlement_price=110,
|
||||
market_id=perps_market,
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_fn(10)
|
||||
vega.wait_for_total_catchup()
|
||||
return perps_market
|
||||
|
||||
@@ -110,7 +108,6 @@ def test_perps_market_termination_proposed(page: Page, vega: VegaServiceNull):
|
||||
forward_time_to_enactment=False,
|
||||
)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
banner_text = page.get_by_test_id(
|
||||
@@ -135,7 +132,6 @@ def test_perps_market_terminated(page: Page, vega: VegaServiceNull):
|
||||
approve_proposal=True,
|
||||
forward_time_to_enactment=True,
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ def check_pnl_color_value(element, expected_color, expected_value):
|
||||
assert color == expected_color, f"Unexpected color: {color}"
|
||||
assert value == expected_value, f"Unexpected value: {value}"
|
||||
|
||||
|
||||
#TODO move this test to jest
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_pnl(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
page.set_viewport_size({"width": 1748, "height": 977})
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import os
|
||||
import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
|
||||
#TODO migrate to jest
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted", "continuous_market")
|
||||
def test_ledger_entries_downloads(page: Page):
|
||||
page.goto("/#/portfolio")
|
||||
page.get_by_test_id("Ledger entries").click()
|
||||
expect(page.get_by_test_id("ledger-download-button")).to_be_enabled()
|
||||
# 7007-LEEN-001
|
||||
page.get_by_test_id("ledger-download-button").click()
|
||||
# 7007-LEEN-009
|
||||
expect(page.get_by_test_id("toast-content")).to_contain_text(("Your file is ready"))
|
||||
# Get the user's Downloads directory
|
||||
downloads_directory = os.path.expanduser("~") + "/Downloads/"
|
||||
# Start waiting for the download
|
||||
with page.expect_download() as download_info:
|
||||
# Perform the action that initiates download
|
||||
page.get_by_role("link", name="Get file here").click()
|
||||
|
||||
download = download_info.value
|
||||
# Wait for the download process to complete and save the downloaded file in the Downloads directory
|
||||
download.save_as(os.path.join(downloads_directory, download.suggested_filename))
|
||||
|
||||
# Verify the download by asserting that the file exists
|
||||
downloaded_file_path = os.path.join(
|
||||
downloads_directory, download.suggested_filename
|
||||
)
|
||||
assert os.path.exists(
|
||||
downloaded_file_path
|
||||
), f"Download failed! File not found at: {downloaded_file_path}"
|
||||
@@ -15,14 +15,13 @@ def test_closed_market_position(vega: VegaServiceNull, page: Page):
|
||||
settlement_price=110,
|
||||
market_id=market_id,
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
page.goto(f"/#/markets/{market_id}")
|
||||
expect(page.locator(".ag-overlay-panel")).to_have_text("No positions")
|
||||
page.get_by_test_id("open-transfer").click()
|
||||
tab = page.get_by_test_id("tab-positions")
|
||||
table = tab.locator(".ag-center-cols-container")
|
||||
table = tab.locator('[class="ag-body ag-layout-normal"]')
|
||||
market = table.locator("[col-id='marketCode']")
|
||||
expect(market.get_by_test_id("stack-cell-primary")).to_have_text("BTC:DAI_2023")
|
||||
page.get_by_test_id("open-transfer").click()
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import pytest
|
||||
import vega_sim.proto.vega as vega_protos
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.null_service import VegaServiceNull
|
||||
from actions.utils import next_epoch
|
||||
from wallet_config import MM_WALLET, PARTY_A, PARTY_B
|
||||
from vega_sim.service import MarketStateUpdateType
|
||||
import vega_sim.api.governance as governance
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted", "auth")
|
||||
def test_filtered_cards(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
|
||||
vega.update_network_parameter(
|
||||
MM_WALLET.name, parameter="reward.asset", new_value=tDAI_asset_id
|
||||
)
|
||||
vega.mint(key_name=PARTY_B.name, asset=tDAI_asset_id, amount=100000)
|
||||
vega.mint(key_name=PARTY_A.name, asset=tDAI_asset_id, amount=100000)
|
||||
next_epoch(vega=vega)
|
||||
vega.recurring_transfer(
|
||||
from_key_name=PARTY_A.name,
|
||||
from_account_type=vega_protos.vega.ACCOUNT_TYPE_GENERAL,
|
||||
to_account_type=vega_protos.vega.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
|
||||
asset=tDAI_asset_id,
|
||||
reference="reward",
|
||||
markets=[continuous_market],
|
||||
asset_for_metric=tDAI_asset_id,
|
||||
metric=vega_protos.vega.DISPATCH_METRIC_MAKER_FEES_PAID,
|
||||
lock_period=5,
|
||||
amount=100,
|
||||
factor=1.0,
|
||||
)
|
||||
vega.submit_order(
|
||||
trading_key=PARTY_B.name,
|
||||
market_id=continuous_market,
|
||||
order_type="TYPE_MARKET",
|
||||
time_in_force="TIME_IN_FORCE_IOC",
|
||||
side="SIDE_BUY",
|
||||
volume=1,
|
||||
)
|
||||
vega.submit_order(
|
||||
trading_key=PARTY_A.name,
|
||||
market_id=continuous_market,
|
||||
order_type="TYPE_MARKET",
|
||||
time_in_force="TIME_IN_FORCE_IOC",
|
||||
side="SIDE_BUY",
|
||||
volume=1,
|
||||
)
|
||||
next_epoch(vega=vega)
|
||||
|
||||
vega.update_market_state(
|
||||
market_id=continuous_market,
|
||||
proposal_key=MM_WALLET.name,
|
||||
market_state=MarketStateUpdateType.Suspend,
|
||||
forward_time_to_enactment=True,
|
||||
)
|
||||
next_epoch(vega=vega)
|
||||
page.goto("/#/rewards")
|
||||
expect(page.locator(".from-vega-cdark-400")).to_be_visible()
|
||||
governance.submit_oracle_data(
|
||||
wallet=vega.wallet,
|
||||
payload={"trading.terminated": "true"},
|
||||
key_name="FJMKnwfZdd48C8NqvYrG",
|
||||
)
|
||||
next_epoch(vega=vega)
|
||||
page.reload()
|
||||
expect(page.locator(".from-vega-cdark-400")).not_to_be_in_viewport()
|
||||
@@ -1,36 +0,0 @@
|
||||
import pytest
|
||||
from playwright.sync_api import expect, Page
|
||||
|
||||
settings_icon = "icon-cog"
|
||||
settings_column_btn = "popover-trigger"
|
||||
settings_close_btn = "settings-close"
|
||||
split_view_view = "split-view-view"
|
||||
|
||||
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
|
||||
def test_column_settings_is_visible(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
expect(page.get_by_test_id(split_view_view).get_by_test_id(settings_column_btn)).to_be_visible()
|
||||
page.goto("/#/portfolio")
|
||||
expect(page.get_by_test_id(split_view_view).get_by_test_id(settings_column_btn).nth(0)).to_be_visible()
|
||||
expect(page.get_by_test_id(split_view_view).get_by_test_id(settings_column_btn).nth(1)).to_be_visible()
|
||||
page.goto(f"/#/markets/all")
|
||||
expect(page.get_by_test_id(settings_column_btn)).to_be_visible()
|
||||
page.click('[data-testid="Proposed markets"]')
|
||||
expect(page.get_by_test_id(settings_column_btn)).to_be_visible()
|
||||
page.click('[data-testid="Closed markets"]')
|
||||
expect(page.get_by_test_id(settings_column_btn)).to_be_visible()
|
||||
|
||||
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
|
||||
def test_can_reset_columns_state(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/all")
|
||||
col_market = page.locator('[col-id="tradableInstrument.instrument.code"]').first
|
||||
col_settlement_asset = page.locator('[col-id="tradableInstrument.instrument.product.settlementAsset.symbol"]').first
|
||||
col_market.drag_to(col_settlement_asset)
|
||||
|
||||
# Check the attribute of the dragged element
|
||||
attribute_value = col_market.get_attribute("aria-colindex")
|
||||
assert attribute_value != "1"
|
||||
page.get_by_test_id(settings_column_btn).click()
|
||||
page.get_by_role("button", name="Reset Columns").click()
|
||||
attribute_value_after_reset = col_market.get_attribute("aria-colindex")
|
||||
assert attribute_value_after_reset == "1"
|
||||
@@ -149,7 +149,5 @@ def provide_successor_liquidity(
|
||||
)
|
||||
|
||||
submit_order(vega, "Key 1", market_id, "SIDE_BUY", 1, 110)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import pytest
|
||||
import re
|
||||
import logging
|
||||
from playwright.sync_api import expect
|
||||
from actions.vega import submit_order
|
||||
from conftest import init_vega
|
||||
from playwright.sync_api import Page
|
||||
from vega_sim.null_service import VegaServiceNull
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega():
|
||||
with init_vega() as vega:
|
||||
yield vega
|
||||
|
||||
|
||||
# Could be turned into a helper function in the future.
|
||||
def verify_data_grid(page: Page, data_test_id, expected_pattern):
|
||||
page.get_by_test_id(data_test_id).click()
|
||||
# Required so that we can get liquidation price
|
||||
expect(
|
||||
page.locator(
|
||||
f'[data-testid^="tab-{data_test_id.lower()}"] >> .ag-center-cols-container .ag-row-first'
|
||||
)
|
||||
).to_be_visible()
|
||||
actual_text = page.locator(
|
||||
f'[data-testid^="tab-{data_test_id.lower()}"] >> .ag-center-cols-container'
|
||||
).text_content()
|
||||
lines = actual_text.strip().split("\n")
|
||||
for expected, actual in zip(expected_pattern, lines):
|
||||
# We are using regex so that we can run tests in different timezones.
|
||||
if re.match(r"^\\d", expected): # check if it's a regex
|
||||
if re.search(expected, actual):
|
||||
logger.info(f"Matched: {expected} == {actual}")
|
||||
else:
|
||||
logger.info(f"Not Matched: {expected} != {actual}")
|
||||
raise AssertionError(f"Pattern does not match: {expected} != {actual}")
|
||||
else: # it's not a regex, so we escape it
|
||||
if re.search(re.escape(expected), actual):
|
||||
logger.info(f"Matched: {expected} == {actual}")
|
||||
else:
|
||||
logger.info(f"Not Matched: {expected} != {actual}")
|
||||
raise AssertionError(f"Pattern does not match: {expected} != {actual}")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_limit_order_new_trade_top_of_list(
|
||||
continuous_market, vega: VegaServiceNull, page: Page
|
||||
):
|
||||
submit_order(vega, "Key 1", continuous_market, "SIDE_BUY", 1, 110)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
expected_trade = [
|
||||
"103.50",
|
||||
"1",
|
||||
r"\d{1,2}/\d{1,2}/\d{4},\s*\d{1,2}:\d{2}:\d{2}\s*(?:AM|PM)" "107.50",
|
||||
"1",
|
||||
r"\d{1,2}/\d{1,2}/\d{4},\s*\d{1,2}:\d{2}:\d{2}\s*(?:AM|PM)",
|
||||
]
|
||||
# 6005-THIS-001
|
||||
# 6005-THIS-002
|
||||
# 6005-THIS-003
|
||||
# 6005-THIS-004
|
||||
# 6005-THIS-005
|
||||
# 6005-THIS-006
|
||||
verify_data_grid(page, "Trades", expected_trade)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_price_copied_to_deal_ticket(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id("Trades").click()
|
||||
page.locator("[col-id=price]").last.click()
|
||||
# 6005-THIS-007
|
||||
expect(page.get_by_test_id("order-price")).to_have_value("107.50000")
|
||||
@@ -22,8 +22,6 @@ def test_trade_match_table(opening_auction_market: str, vega: VegaServiceNull, p
|
||||
price=10e15,
|
||||
wait=False,
|
||||
)
|
||||
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -34,7 +32,6 @@ def test_trade_match_table(opening_auction_market: str, vega: VegaServiceNull, p
|
||||
"SIDE_BUY",
|
||||
[[5, 110], [5, 105], [1, 50]],
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -45,7 +42,6 @@ def test_trade_match_table(opening_auction_market: str, vega: VegaServiceNull, p
|
||||
"SIDE_SELL",
|
||||
[[5, 90], [5, 95], [1, 150]],
|
||||
)
|
||||
vega.forward("60s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ def test_transfer_submit(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
|
||||
page.locator('[data-testid=transfer-form] [type="submit"]').click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
expected_confirmation_text = re.compile(
|
||||
@@ -142,14 +141,12 @@ def test_transfer_vesting_below_minimum(
|
||||
asset=asset_id,
|
||||
amount=24.999999,
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(10)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
page.get_by_test_id("use-max-button").first.click()
|
||||
page.locator('[data-testid=transfer-form] [type="submit"]').click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
expected_confirmation_text = re.compile(
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
import pytest
|
||||
import re
|
||||
import json
|
||||
from playwright.sync_api import Page, expect, Route
|
||||
from conftest import init_vega
|
||||
from fixtures.market import setup_continuous_market
|
||||
|
||||
order_size = "order-size"
|
||||
order_price = "order-price"
|
||||
place_order = "place-order"
|
||||
order_side_sell = "order-side-SIDE_SELL"
|
||||
market_order = "order-type-Market"
|
||||
tif = "order-tif"
|
||||
expire = "expire"
|
||||
api_request_match = r"http://localhost:\d+/api/v2/requests"
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega(request):
|
||||
with init_vega(request) as vega:
|
||||
yield vega
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def continuous_market(vega):
|
||||
return setup_continuous_market(vega)
|
||||
|
||||
|
||||
def handle_route_connection_lost(route: Route, request):
|
||||
if request.method == "POST" and re.match(api_request_match, request.url):
|
||||
route.fulfill(
|
||||
status=200,
|
||||
headers={"Content-Type": "application/json"},
|
||||
body='{"jsonrpc": "2.0", "id": "1"}',
|
||||
)
|
||||
else:
|
||||
route.continue_()
|
||||
|
||||
|
||||
def handle_route_connection_rejected(route: Route, request):
|
||||
if request.method == "POST" and re.match(api_request_match, request.url):
|
||||
custom_response = {
|
||||
"jsonrpc": "2.0",
|
||||
"error": {
|
||||
"code": 3001,
|
||||
"data": "the user rejected the wallet connection",
|
||||
"message": "User error",
|
||||
},
|
||||
"id": "0",
|
||||
}
|
||||
route.fulfill(
|
||||
status=400,
|
||||
headers={"Content-Type": "application/json"},
|
||||
body=json.dumps(custom_response),
|
||||
)
|
||||
else:
|
||||
route.continue_()
|
||||
|
||||
|
||||
def assert_connection_approve(route: Route, request, page: Page):
|
||||
if request.method == "POST" and re.match(api_request_match, request.url):
|
||||
expect(page.get_by_test_id("toast-content")).to_have_text(
|
||||
"Please go to your Vega wallet application and approve or reject the transaction."
|
||||
)
|
||||
else:
|
||||
route.continue_()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_wallet_connection_error(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.route("**/*", handle_route_connection_lost)
|
||||
page.get_by_test_id("connect-vega-wallet").click()
|
||||
page.get_by_test_id("connector-jsonRpc").click()
|
||||
expect(page.get_by_test_id("wallet-dialog-title")).to_have_text(
|
||||
"Something went wrong"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_wallet_connection_rejected(continuous_market, page: Page):
|
||||
# 0002-WCON-002
|
||||
# 0002-WCON-005
|
||||
# 0002-WCON-007
|
||||
# 0002-WCON-015
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.route("**/*", handle_route_connection_rejected)
|
||||
page.get_by_test_id("connect-vega-wallet").click()
|
||||
page.get_by_test_id("connector-jsonRpc").click()
|
||||
expect(page.get_by_test_id("dialog-content").nth(1)).to_have_text(
|
||||
"User errorthe user rejected the wallet connectionTry againAbout the Vega wallet | Supported browsers "
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_wallet_connection_error_transaction(continuous_market, page: Page):
|
||||
# 0003-WTXN-009
|
||||
# 0003-WTXN-011
|
||||
# 0002-WCON-016
|
||||
# 0003-WTXN-008
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(order_size).fill("10")
|
||||
page.get_by_test_id(order_price).fill("120")
|
||||
page.route("**/*", handle_route_connection_lost)
|
||||
page.get_by_test_id(place_order).click()
|
||||
expect(page.get_by_test_id("toast-content")).to_have_text(
|
||||
"Wallet disconnectedThe connection to your Vega Wallet has been lost.Connect vega wallet"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_wallet_transaction_rejected(continuous_market, page: Page):
|
||||
# 0003-WTXN-007
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(order_size).fill("10")
|
||||
page.get_by_test_id(order_price).fill("120")
|
||||
page.route("**/*", handle_route_connection_rejected)
|
||||
page.get_by_test_id(place_order).click()
|
||||
expect(page.get_by_test_id("toast-content")).to_have_text(
|
||||
"Error occurredthe user rejected the wallet connection"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_wallet_connection_approve(continuous_market, page: Page):
|
||||
# 0002-WCON-005
|
||||
# 0002-WCON-007
|
||||
# 0002-WCON-009
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(order_size).fill("10")
|
||||
page.get_by_test_id(order_price).fill("120")
|
||||
page.route("**/*", assert_connection_approve)
|
||||
page.get_by_test_id(place_order).click()
|
||||
@@ -1,62 +0,0 @@
|
||||
import {
|
||||
Intent,
|
||||
useToasts,
|
||||
ToastHeading,
|
||||
CLOSE_AFTER,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useT } from '../use-t';
|
||||
import { VegaWalletConnectButton } from '../../components/vega-wallet-connect-button';
|
||||
|
||||
const WALLET_DISCONNECTED_TOAST_ID = 'WALLET_DISCONNECTED_TOAST_ID';
|
||||
|
||||
export const useWalletDisconnectedToasts = () => {
|
||||
const t = useT();
|
||||
const [hasToast, setToast, updateToast] = useToasts((state) => [
|
||||
state.hasToast,
|
||||
state.setToast,
|
||||
state.update,
|
||||
]);
|
||||
const { isAlive } = useVegaWallet();
|
||||
|
||||
const toast = useMemo(
|
||||
() => ({
|
||||
id: WALLET_DISCONNECTED_TOAST_ID,
|
||||
intent: Intent.Danger,
|
||||
content: (
|
||||
<>
|
||||
<ToastHeading>{t('Wallet connection lost')}</ToastHeading>
|
||||
<p>{t('The connection to the Vega wallet has been lost.')}</p>
|
||||
<p className="mt-2">
|
||||
<VegaWalletConnectButton
|
||||
intent={Intent.Danger}
|
||||
onClick={() => {
|
||||
updateToast(WALLET_DISCONNECTED_TOAST_ID, {
|
||||
hidden: true,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
onClose: () => {
|
||||
updateToast(WALLET_DISCONNECTED_TOAST_ID, {
|
||||
hidden: true,
|
||||
});
|
||||
},
|
||||
closeAfter: CLOSE_AFTER,
|
||||
}),
|
||||
[t, updateToast]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAlive === false) {
|
||||
if (hasToast(WALLET_DISCONNECTED_TOAST_ID)) {
|
||||
updateToast(WALLET_DISCONNECTED_TOAST_ID, { hidden: false });
|
||||
} else {
|
||||
setToast(toast);
|
||||
}
|
||||
}
|
||||
}, [hasToast, isAlive, setToast, t, toast, updateToast]);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ToastsContainer, useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { Intent, ToastsContainer, useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { useProposalToasts } from '@vegaprotocol/proposals';
|
||||
import { useVegaTransactionToasts } from '@vegaprotocol/web3';
|
||||
import { useEthereumTransactionToasts } from '@vegaprotocol/web3';
|
||||
@@ -6,7 +6,26 @@ import { useEthereumWithdrawApprovalsToasts } from '@vegaprotocol/web3';
|
||||
import { useReadyToWithdrawalToasts } from '@vegaprotocol/withdraws';
|
||||
import { Links } from '../lib/links';
|
||||
import { useReferralToasts } from '../client-pages/referrals/hooks/use-referral-toasts';
|
||||
import { useWalletDisconnectedToasts } from '../lib/hooks/use-wallet-disconnected-toasts';
|
||||
import {
|
||||
useWalletDisconnectToastActions,
|
||||
useWalletDisconnectedToasts,
|
||||
} from '@vegaprotocol/web3';
|
||||
import { VegaWalletConnectButton } from '../components/vega-wallet-connect-button';
|
||||
|
||||
const WalletDisconnectAdditionalContent = () => {
|
||||
const { hideToast } = useWalletDisconnectToastActions();
|
||||
return (
|
||||
<p className="mt-2">
|
||||
<VegaWalletConnectButton
|
||||
intent={Intent.Danger}
|
||||
onClick={() => {
|
||||
// hide toast when clicked on `Connect`
|
||||
hideToast();
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export const ToastsManager = () => {
|
||||
useProposalToasts();
|
||||
@@ -17,7 +36,7 @@ export const ToastsManager = () => {
|
||||
withdrawalsLink: Links.PORTFOLIO(),
|
||||
});
|
||||
useReferralToasts();
|
||||
useWalletDisconnectedToasts();
|
||||
useWalletDisconnectedToasts(<WalletDisconnectAdditionalContent />);
|
||||
|
||||
const toasts = useToasts((store) => store.toasts);
|
||||
return <ToastsContainer order="desc" toasts={toasts} />;
|
||||
|
||||
@@ -67,6 +67,7 @@ const defaultColDef = {
|
||||
sortable: true,
|
||||
tooltipComponent: TooltipCellComponent,
|
||||
comparator: accountValuesComparator,
|
||||
minWidth: 150,
|
||||
};
|
||||
export interface GetRowsParams extends Omit<IGetRowsParams, 'successCallback'> {
|
||||
successCallback(rowsThisBlock: AccountFields[], lastRow?: number): void;
|
||||
@@ -139,6 +140,8 @@ export const AccountTable = ({
|
||||
{
|
||||
headerName: t('Asset'),
|
||||
field: 'asset.symbol',
|
||||
pinned: true,
|
||||
minWidth: 75,
|
||||
headerTooltip: t(
|
||||
'Asset is the collateral that is deposited into the Vega protocol.'
|
||||
),
|
||||
@@ -253,8 +256,8 @@ export const AccountTable = ({
|
||||
colId: 'accounts-actions',
|
||||
field: 'asset.id',
|
||||
...COL_DEFS.actions,
|
||||
minWidth: showDepositButton ? 105 : COL_DEFS.actions.minWidth,
|
||||
maxWidth: showDepositButton ? 105 : COL_DEFS.actions.maxWidth,
|
||||
minWidth: showDepositButton ? 110 : COL_DEFS.actions.minWidth,
|
||||
maxWidth: showDepositButton ? 110 : COL_DEFS.actions.maxWidth,
|
||||
cellRenderer: ({
|
||||
value: assetId,
|
||||
node,
|
||||
|
||||
@@ -23,7 +23,9 @@ import { AccountType } from '@vegaprotocol/types';
|
||||
const defaultColDef = {
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
minWidth: 100,
|
||||
};
|
||||
|
||||
interface BreakdownTableProps extends AgGridReactProps {
|
||||
data: AccountFields[] | null;
|
||||
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
||||
@@ -32,12 +34,13 @@ interface BreakdownTableProps extends AgGridReactProps {
|
||||
const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
|
||||
({ data }, ref) => {
|
||||
const t = useT();
|
||||
const coldefs = useMemo(() => {
|
||||
const colDefs = useMemo(() => {
|
||||
const defs: ColDef[] = [
|
||||
{
|
||||
headerName: t('Market'),
|
||||
field: 'market.tradableInstrument.instrument.code',
|
||||
minWidth: 200,
|
||||
width: 90,
|
||||
pinned: true,
|
||||
sort: 'desc',
|
||||
cellRenderer: ({
|
||||
value,
|
||||
@@ -141,7 +144,7 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
|
||||
components={{ PriceCell, ProgressBarCell }}
|
||||
tooltipShowDelay={500}
|
||||
defaultColDef={defaultColDef}
|
||||
columnDefs={coldefs}
|
||||
columnDefs={colDefs}
|
||||
domLayout="autoHeight"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -15,7 +15,6 @@ export async function proposeMarket(publicKey: string) {
|
||||
log('sending proposal tx');
|
||||
const proposalTx = createNewMarketProposal();
|
||||
const result = await sendVegaTx(publicKey, proposalTx);
|
||||
|
||||
return result.result;
|
||||
}
|
||||
|
||||
@@ -119,6 +118,7 @@ function createNewMarketProposal(): ProposalSubmissionBody {
|
||||
timeWindow: '3600',
|
||||
scalingFactor: 10,
|
||||
},
|
||||
// FIXME: workaround because of https://github.com/vegaprotocol/vega/issues/10343
|
||||
triggeringRatio: '0.7',
|
||||
auctionExtension: '1',
|
||||
},
|
||||
|
||||
@@ -9,4 +9,7 @@ export const COL_DEFS = {
|
||||
type: 'rightAligned',
|
||||
pinned: 'right' as const,
|
||||
},
|
||||
default: {
|
||||
minWidth: 100,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -329,8 +329,9 @@ export const DealTicket = ({
|
||||
|
||||
const marketTradingModeError = validateMarketTradingMode(
|
||||
marketTradingMode,
|
||||
t('Trading terminated')
|
||||
t('No trading')
|
||||
);
|
||||
|
||||
if (marketTradingModeError !== true) {
|
||||
return {
|
||||
message: marketTradingModeError,
|
||||
|
||||
@@ -11,9 +11,6 @@ export function generateMarket(override?: PartialDeep<Market>): Market {
|
||||
positionDecimalPlaces: 1,
|
||||
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
state: Schema.MarketState.STATE_ACTIVE,
|
||||
liquidityMonitoringParameters: {
|
||||
triggeringRatio: '1',
|
||||
},
|
||||
marketTimestamps: {
|
||||
__typename: 'MarketTimestamps',
|
||||
close: '',
|
||||
@@ -75,7 +72,6 @@ export function generateMarket(override?: PartialDeep<Market>): Market {
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
},
|
||||
|
||||
fees: {
|
||||
factors: {
|
||||
makerFee: '0.001',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user