Compare commits

...
73 changed files with 3078 additions and 2105 deletions
@@ -1,7 +1,7 @@
import { getNewAssetTxBody } from '../support/governance.functions';
context('Proposal page', { tags: '@smoke' }, function () {
describe('Verify elements on page', function () {
describe.skip('Verify elements on page', function () {
const proposalHeading = 'proposals-heading';
const dateTimeRegex =
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
@@ -7,7 +7,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
});
describe('Links and buttons', function () {
it.skip('should have link for proposal page', function () {
it('should have link for proposal page', function () {
cy.getByTestId('home-proposals').within(() => {
cy.get('[href="/proposals"]')
.should('exist')
@@ -51,7 +51,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
});
});
it.skip('should have external link for governance', function () {
it('should have external link for governance', function () {
cy.getByTestId('home-proposals').within(() => {
cy.getByTestId('external-link')
.should('have.attr', 'href')
@@ -59,7 +59,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
});
});
it.skip('should have link for validator page', function () {
it('should have link for validator page', function () {
cy.getByTestId('home-validators').within(() => {
cy.get('[href="/validators"]')
.first()
@@ -68,7 +68,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
});
});
it.skip('should have external link for validators', function () {
it('should have external link for validators', function () {
cy.getByTestId('home-validators').within(() => {
cy.getByTestId('external-link')
.should('have.attr', 'href')
@@ -79,29 +79,29 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
});
});
it.skip('should have information on active nodes', function () {
it('should have information on active nodes', function () {
cy.getByTestId('node-information')
.first()
.should('contain.text', '2')
.should('contain.text', '1')
.and('contain.text', 'active nodes');
});
it.skip('should have information on consensus nodes', function () {
it('should have information on consensus nodes', function () {
cy.getByTestId('node-information')
.last()
.should('contain.text', '2')
.should('contain.text', '1')
.and('contain.text', 'consensus nodes');
});
it.skip('should contain link to specific validators', function () {
it('should contain link to specific validators', function () {
cy.getByTestId('validators')
.should('have.length', '2')
.should('have.length', '1')
.each(($validator) => {
cy.wrap($validator).find('a').should('have.attr', 'href');
});
});
it.skip('should have link for rewards page', function () {
it('should have link for rewards page', function () {
cy.getByTestId('home-rewards').within(() => {
cy.get('[href="/rewards"]')
.first()
@@ -110,7 +110,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
});
});
it.skip('should have link for withdrawal page', function () {
it('should have link for withdrawal page', function () {
cy.getByTestId('home-vega-token').within(() => {
cy.get('[href="/token/withdraw"]')
.first()
@@ -132,7 +132,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
});
// 0006-NETW-003 0006-NETW-008 0006-NETW-009 0006-NETW-010 0006-NETW-012 0006-NETW-013 0006-NETW-017 0006-NETW-018 0006-NETW-019 0006-NETW-020
it.skip('should have option to switch to different network node', function () {
it('should have option to switch to different network node', function () {
cy.getByTestId('git-network-data').within(() => {
cy.getByTestId('link').click();
});
@@ -159,7 +159,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
cy.getByTestId('node-url-custom').click({ force: true });
cy.get('input').should('exist');
cy.getByTestId('connect').should('be.disabled');
cy.getByTestId('icon-cross').click();
cy.getByTestId('dialog-close').click();
});
it('should display eth data', function () {
@@ -33,12 +33,12 @@ context(
verifyTabHighlighted(navigation.proposals);
});
it.skip('should have GOVERNANCE header visible', function () {
it('should have GOVERNANCE header visible', function () {
verifyPageHeader('Proposals');
});
// 3002-PROP-023 3004-PMAC-002 3005-PASN-002 3006-PASC-002 3007-PNEC-002 3008-PFRO-003
it.skip('new proposal page should have button for link to more information on proposals', function () {
it('new proposal page should have button for link to more information on proposals', function () {
cy.getByTestId('new-proposal-link').click();
cy.url().should('include', '/proposals/propose/raw');
cy.contains('To see Explorer data on proposals visit').within(() => {
@@ -73,7 +73,7 @@ context(
navigateTo(navigation.proposals);
});
it.skip('should be able to see a working link for - find out more about Vega governance', function () {
it('should be able to see a working link for - find out more about Vega governance', function () {
// 3001-VOTE-001 // 3002-PROP-001
cy.getByTestId(proposalDocumentationLink)
.should('be.visible')
@@ -40,10 +40,10 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
verifyConnectedToPubKey();
});
it('Able to connect public key via wallet and view assets in wallet', function () {
it.skip('Able to connect public key via wallet and view assets in wallet', function () {
verifyConnectedToPubKey();
cy.getByTestId('currency-title', { timeout: 10000 })
.should('have.length.at.least', 4)
.should('have.length.at.least', 2)
.and('contain.text', 'USDC (fake)');
});
@@ -46,11 +46,11 @@ context('Validators Page - verify elements on page', function () {
// @ts-ignore clash between jest and cypress
describe('with wallets disconnected', { tags: '@smoke' }, function () {
it.skip('Should have validators tab highlighted', function () {
it('Should have validators tab highlighted', function () {
verifyTabHighlighted(navigation.validators);
});
it.skip('Should have validators ON VEGA header visible', function () {
it('Should have validators ON VEGA header visible', function () {
verifyPageHeader('Validators');
});
@@ -192,7 +192,7 @@ context('Validators Page - verify elements on page', function () {
});
// 1002-STKE-006
it.skip('Should be able to see validator name', function () {
it('Should be able to see validator name', function () {
cy.getByTestId(validatorTitle).should('not.be.empty');
});
+3 -3
View File
@@ -33,7 +33,7 @@ LC_ALL="en_US.UTF-8"
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=false
NX_UPDATE_MARKET_STATE=false
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_GOVERNANCE_TRANSFERS=false
NX_GOVERNANCE_TRANSFERS=true
+3
View File
@@ -62,6 +62,9 @@ const cache: InMemoryCacheConfig = {
Account: {
keyFields: false,
},
Instrument: {
keyFields: ['code'],
},
Delegation: {
keyFields: false,
// Only get full updates
@@ -1,7 +1,8 @@
import classNames from 'classnames';
import { type ReactNode } from 'react';
interface HeadingProps {
title?: string;
title?: ReactNode;
centerContent?: boolean;
marginTop?: boolean;
marginBottom?: boolean;
@@ -54,11 +54,8 @@ const ProposalTypeTags = ({
if (proposal.__typename === 'BatchProposal') {
return (
<div data-testid="proposal-type" className="flex gap-1">
{proposal.subProposals?.map((subProposal, i) => {
if (!subProposal?.terms) return null;
return <ProposalTypeTag key={i} terms={subProposal.terms} />;
})}
<div data-testid="proposal-type">
<ProposalInfoLabel variant="secondary">BatchProposal</ProposalInfoLabel>
</div>
);
}
@@ -140,6 +137,9 @@ const ProposalDetails = ({
);
}
case 'UpdateMarketState': {
const marketPageLink = consoleLink(
CONSOLE_MARKET_PAGE.replace(':marketId', terms.change.market.id)
);
return (
<span>
{featureFlags.UPDATE_MARKET_STATE &&
@@ -161,24 +161,16 @@ const ProposalDetails = ({
</button>
</CopyWithTooltip>
<Tooltip description={t('OpenInConsole')} align="center">
<button
<Link
className="inline-block px-1"
onClick={() => {
const marketPageLink = consoleLink(
CONSOLE_MARKET_PAGE.replace(
':marketId',
// @ts-ignore ts doesn't like this field even though its already a string above???
terms.change.market.id
)
);
window.open(marketPageLink, '_blank');
}}
to={marketPageLink}
target="_blank"
>
<VegaIcon
size={20}
name={VegaIconNames.OPEN_EXTERNAL}
/>
</button>
</Link>
</Tooltip>
</span>
</span>
@@ -188,6 +180,10 @@ const ProposalDetails = ({
);
}
case 'UpdateMarket': {
const marketPageLink = consoleLink(
CONSOLE_MARKET_PAGE.replace(':marketId', terms.change.marketId)
);
return (
<>
<span>{t('UpdateToMarket')}: </span>
@@ -205,21 +201,13 @@ const ProposalDetails = ({
</button>
</CopyWithTooltip>
<Tooltip description={t('OpenInConsole')} align="center">
<button
<Link
className="inline-block px-1"
onClick={() => {
const marketPageLink = consoleLink(
CONSOLE_MARKET_PAGE.replace(
':marketId',
// @ts-ignore ts doesn't like this field even though its already a string above???
terms.change.marketId
)
);
window.open(marketPageLink, '_blank');
}}
target="_blank"
to={marketPageLink}
>
<VegaIcon size={20} name={VegaIconNames.OPEN_EXTERNAL} />
</button>
</Link>
</Tooltip>
</span>
</span>
@@ -324,7 +312,7 @@ const ProposalDetails = ({
{proposal.subProposals.map((p, i) => {
if (!p?.terms) return null;
return (
<li key={i} className="flex gap-3">
<li key={i} className="flex gap-3 items-center">
<span className={getIndicatorStyle(i + 1)}>{i + 1}</span>
<span>
<div>{renderDetails(p.terms)}</div>
@@ -3,16 +3,8 @@ import { useTranslation } from 'react-i18next';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import {
type BatchProposalFieldsFragment,
type ProposalFieldsFragment,
} from '../../__generated__/Proposals';
export const ProposalJson = ({
proposal,
}: {
proposal: ProposalFieldsFragment | BatchProposalFieldsFragment;
}) => {
export const ProposalJson = ({ proposal }: { proposal?: unknown }) => {
const { t } = useTranslation();
const [showDetails, setShowDetails] = useState(false);
@@ -5,6 +5,11 @@ import {
} from './proposal-market-changes';
import type { JsonValue } from '../../../../components/json-diff';
jest.mock('../proposal/market-name.tsx', () => ({
...jest.requireActual('../proposal/market-name.tsx'),
MarketName: jest.fn(),
}));
describe('applyImmutableKeysFromEarlierVersion', () => {
it('returns an empty object if any argument is not an object or null', () => {
const earlierVersion: JsonValue = null;
@@ -57,21 +62,21 @@ describe('applyImmutableKeysFromEarlierVersion', () => {
describe('ProposalMarketChanges', () => {
it('renders correctly', () => {
const { getByTestId } = render(
<ProposalMarketChanges marketId="market-id" updatedProposal={{}} />
<ProposalMarketChanges marketId="market-id" updateProposalNode={null} />
);
expect(getByTestId('proposal-market-changes')).toBeInTheDocument();
});
it('JsonDiff is not visible when showChanges is false', () => {
const { queryByTestId } = render(
<ProposalMarketChanges marketId="market-id" updatedProposal={{}} />
<ProposalMarketChanges marketId="market-id" updateProposalNode={null} />
);
expect(queryByTestId('json-diff')).not.toBeInTheDocument();
});
it('JsonDiff is visible when showChanges is true', async () => {
const { getByTestId } = render(
<ProposalMarketChanges marketId="market-id" updatedProposal={{}} />
<ProposalMarketChanges marketId="market-id" updateProposalNode={null} />
);
fireEvent.click(getByTestId('proposal-market-changes-toggle'));
expect(getByTestId('json-diff')).toBeInTheDocument();
@@ -1,14 +1,24 @@
import cloneDeep from 'lodash/cloneDeep';
import set from 'lodash/set';
import get from 'lodash/get';
import { JsonDiff } from '../../../../components/json-diff';
import compact from 'lodash/compact';
import orderBy from 'lodash/orderBy';
import { JsonDiff, type JsonValue } from '../../../../components/json-diff';
import { useTranslation } from 'react-i18next';
import { useState } from 'react';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import { SubHeading } from '../../../../components/heading';
import type { JsonValue } from '../../../../components/json-diff';
import { useFetch } from '@vegaprotocol/react-helpers';
import { ENV } from '../../../../config';
import {
useFetchProposal,
useFetchProposals,
flatten,
isBatchProposalNode,
isSingleProposalNode,
type ProposalNode,
type SingleProposalData,
type SubProposalData,
} from '../proposal/proposal-utils';
import { MarketName } from '../proposal/market-name';
const immutableKeys = [
'decimalPlaces',
@@ -18,8 +28,8 @@ const immutableKeys = [
];
export const applyImmutableKeysFromEarlierVersion = (
earlierVersion: JsonValue,
updatedVersion: JsonValue
earlierVersion: unknown,
updatedVersion: unknown
) => {
if (
typeof earlierVersion !== 'object' ||
@@ -35,7 +45,8 @@ export const applyImmutableKeysFromEarlierVersion = (
// Overwrite the immutable keys in the updatedVersionCopy with the earlier values
immutableKeys.forEach((key) => {
set(updatedVersionCopy, key, get(earlierVersion, key));
const earlier = get(earlierVersion, key);
if (earlier) set(updatedVersionCopy, key, earlier);
});
return updatedVersionCopy;
@@ -43,49 +54,84 @@ export const applyImmutableKeysFromEarlierVersion = (
interface ProposalMarketChangesProps {
marketId: string;
updatedProposal: JsonValue;
/** This are the changes from proposal */
updateProposalNode: ProposalNode | null;
indicator?: number;
}
export const ProposalMarketChanges = ({
marketId,
updatedProposal,
updateProposalNode,
indicator,
}: ProposalMarketChangesProps) => {
const { t } = useTranslation();
const [showChanges, setShowChanges] = useState(false);
const {
state: { data },
} = useFetch(`${ENV.rest}governance?proposalId=${marketId}`, undefined, true);
const { data: originalProposalData } = useFetchProposal({
proposalId: marketId,
});
const {
state: { data: enactedProposalData },
} = useFetch(
`${ENV.rest}governances?proposalState=STATE_ENACTED&proposalType=TYPE_UPDATE_MARKET`,
undefined,
true
const { data: enactedProposalsData } = useFetchProposals({
proposalState: 'STATE_ENACTED',
proposalType: 'TYPE_UPDATE_MARKET',
});
let updateProposal: SingleProposalData | SubProposalData | undefined;
if (isBatchProposalNode(updateProposalNode)) {
updateProposal = updateProposalNode.proposals.find(
(p, i) =>
p.terms.updateMarket?.marketId === marketId &&
(indicator != null ? i === indicator - 1 : true)
);
}
if (isSingleProposalNode(updateProposalNode)) {
updateProposal = updateProposalNode.proposal;
}
// this should get the proposal before the current one
const enactedUpdateMarketProposals = orderBy(
compact(
flatten(enactedProposalsData).filter((enacted) => {
const related = enacted.terms.updateMarket?.marketId === marketId;
const notCurrent =
enacted.id !== updateProposal?.id ||
('batchId' in enacted && enacted.batchId !== updateProposal.id);
const beforeCurrent =
Number(enacted.terms.enactmentTimestamp) <
Number(updateProposal?.terms.enactmentTimestamp);
return related && notCurrent && beforeCurrent;
})
),
[(proposal) => Number(proposal.terms.enactmentTimestamp)],
'desc'
);
// @ts-ignore no types here :-/
const enacted = enactedProposalData?.connection?.edges
.filter(
// @ts-ignore no type here
({ node }) => node?.proposal?.terms?.updateMarket?.marketId === marketId
)
// @ts-ignore no type here
.sort((a, b) => {
return (
new Date(a?.node?.terms?.enactmentTimestamp).getTime() -
new Date(b?.node?.terms?.enactmentTimestamp).getTime()
);
});
const latestEnactedProposal =
enactedUpdateMarketProposals.length > 0
? enactedUpdateMarketProposals[0]
: undefined;
const latestEnactedProposal = enacted?.length
? enacted[enacted.length - 1]
: undefined;
let originalProposal;
if (isBatchProposalNode(originalProposalData)) {
originalProposal = originalProposalData.proposals.find(
(proposal) => proposal.id === marketId && proposal.terms.newMarket != null
);
}
if (isSingleProposalNode(originalProposalData)) {
originalProposal = originalProposalData.proposal;
}
const originalProposal =
// @ts-ignore no types with useFetch TODO: check this is good
data?.data?.proposal?.terms?.newMarket?.changes;
// LEFT SIDE: update market proposal enacted just before this one
// or original new market proposal
const left =
latestEnactedProposal?.terms.updateMarket?.changes ||
originalProposal?.terms.newMarket?.changes;
// RIGHT SIDE: this update market proposal
const right = applyImmutableKeysFromEarlierVersion(
left,
updateProposal?.terms.updateMarket?.changes
);
return (
<section data-testid="proposal-market-changes">
@@ -94,25 +140,18 @@ export const ProposalMarketChanges = ({
setToggleState={setShowChanges}
dataTestId={'proposal-market-changes-toggle'}
>
<SubHeading title={t('updatesToMarket')} />
<SubHeading
title={
<>
{t('UpdateToMarket')}: <MarketName marketId={marketId} />
</>
}
/>
</CollapsibleToggle>
{showChanges && (
<div className="mb-6">
<JsonDiff
left={latestEnactedProposal || originalProposal}
right={
latestEnactedProposal
? applyImmutableKeysFromEarlierVersion(
latestEnactedProposal,
updatedProposal
)
: applyImmutableKeysFromEarlierVersion(
originalProposal,
updatedProposal
)
}
/>
<JsonDiff left={left as JsonValue} right={right as JsonValue} />
</div>
)}
</section>
@@ -2,6 +2,11 @@ import { fireEvent, render, screen } from '@testing-library/react';
import { ProposalUpdateMarketState } from './proposal-update-market-state';
import { MarketUpdateType } from '@vegaprotocol/types';
jest.mock('../proposal/market-name.tsx', () => ({
...jest.requireActual('../proposal/market-name.tsx'),
MarketName: jest.fn(),
}));
describe('<ProposalUpdateMarketState />', () => {
const suspendProposal = {
__typename: 'UpdateMarketState' as const,
@@ -10,6 +10,7 @@ import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import { SubHeading } from '../../../../components/heading';
import { type UpdateMarketStatesFragment } from '../../__generated__/Proposals';
import { MarketUpdateTypeMapping } from '@vegaprotocol/types';
import { MarketName } from '../proposal/market-name';
interface ProposalUpdateMarketStateProps {
change: UpdateMarketStatesFragment | null;
@@ -20,16 +21,18 @@ export const ProposalUpdateMarketState = ({
}: ProposalUpdateMarketStateProps) => {
const { t } = useTranslation();
const [showDetails, setShowDetails] = useState(false);
let market;
let isTerminate = false;
if (!change) {
if (!change || change.__typename !== 'UpdateMarketState') {
return null;
}
if (change.__typename === 'UpdateMarketState') {
market = change?.market;
isTerminate = change?.updateType === 'MARKET_STATE_UPDATE_TYPE_TERMINATE';
const market = change?.market;
const isTerminate =
change?.updateType === 'MARKET_STATE_UPDATE_TYPE_TERMINATE';
let toggleTitle = t(change.updateType);
if (toggleTitle.length === 0) {
toggleTitle = t('MarketDetails');
}
return (
@@ -39,7 +42,13 @@ export const ProposalUpdateMarketState = ({
setToggleState={setShowDetails}
dataTestId="proposal-market-data-toggle"
>
<SubHeading title={t('MarketDetails')} />
<SubHeading
title={
<>
{toggleTitle}: <MarketName marketId={market?.id} />
</>
}
/>
</CollapsibleToggle>
{showDetails && (
@@ -16,18 +16,31 @@ const getColour = (indicator: number, max = COLOURS.length) => {
export const getStyle = (indicator: number, max = COLOURS.length) =>
classNames({
'bg-vega-yellow-400': 'yellow' === getColour(indicator, max),
'bg-vega-green-400': 'green' === getColour(indicator, max),
'bg-vega-blue-400': 'blue' === getColour(indicator, max),
'bg-vega-purple-400': 'purple' === getColour(indicator, max),
'bg-vega-pink-400': 'pink' === getColour(indicator, max),
'bg-vega-orange-400': 'orange' === getColour(indicator, max),
'bg-vega-red-400': 'red' === getColour(indicator, max),
'bg-vega-clight-600': 'none' === getColour(indicator, max),
'bg-vega-yellow-400 after:bg-vega-yellow-400':
'yellow' === getColour(indicator, max),
'bg-vega-green-400 after:bg-vega-green-400':
'green' === getColour(indicator, max),
'bg-vega-blue-400 after:bg-vega-blue-400':
'blue' === getColour(indicator, max),
'bg-vega-purple-400 after:bg-vega-purple-400':
'purple' === getColour(indicator, max),
'bg-vega-pink-400 after:bg-vega-pink-400':
'pink' === getColour(indicator, max),
'bg-vega-orange-400 after:bg-vega-orange-400':
'orange' === getColour(indicator, max),
'bg-vega-red-400 after:bg-vega-red-400':
'red' === getColour(indicator, max),
'bg-vega-clight-600 after:bg-vega-clight-600':
'none' === getColour(indicator, max),
});
export const getIndicatorStyle = (indicator: number) =>
classNames(
'rounded-sm text-black inline-block px-1 py-1 font-alpha calt h-8',
getStyle(indicator)
'rounded-sm text-black inline-block px-1 py-1 font-alpha calt h-8 w-7 text-center',
'text-border-1',
getStyle(indicator),
// Comment below if you want to remove the "chevron"
'relative mr-[11px]',
'after:absolute after:z-[-1] after:top-1 after:right-[-11px] after:rounded-sm',
"after:w-[22.62px] after:h-[22.62px] after:rotate-45 after:content-['']"
);
@@ -13,6 +13,7 @@ import { ProposalUpdateBenefitTiers } from '../proposal-update-benefit-tiers';
import { ProposalUpdateMarketState } from '../proposal-update-market-state';
import { ProposalVolumeDiscountProgramDetails } from '../proposal-volume-discount-program-details';
import { getIndicatorStyle } from './colours';
import { type ProposalNode } from './proposal-utils';
export const ProposalChangeDetails = ({
proposal,
@@ -22,8 +23,7 @@ export const ProposalChangeDetails = ({
}: {
proposal: Proposal | BatchProposal;
terms: ProposalTermsFieldsFragment;
// eslint-disable-next-line
restData: any;
restData: ProposalNode | null;
indicator?: number;
}) => {
let details = null;
@@ -63,30 +63,13 @@ export const ProposalChangeDetails = ({
}
case 'UpdateMarket': {
if (proposal.id) {
const marketId = terms.change.marketId;
const proposalData = restData?.data?.proposal;
let updatedProposal = null;
// single proposal
if ('terms' in proposalData) {
updatedProposal = proposalData?.terms?.updateMarket?.changes;
}
// batch proposal - need to fish for the actual changes
if (
'batchTerms' in proposalData &&
Array.isArray(proposalData.batchTerms?.changes)
) {
updatedProposal = proposalData?.batchTerms?.changes.find(
(ch: { updateMarket?: { marketId: string } }) =>
ch?.updateMarket?.marketId === marketId
)?.updateMarket?.changes;
}
details = (
<div className="flex flex-col gap-4">
<ProposalMarketData proposalId={proposal.id} />
<ProposalMarketChanges
indicator={indicator}
marketId={terms.change.marketId}
updatedProposal={updatedProposal}
updateProposalNode={restData}
/>
</div>
);
@@ -0,0 +1,261 @@
import compact from 'lodash/compact';
import { ENV } from '../../../../config';
import { useEffect, useState } from 'react';
type Maybe<T> = T | null | undefined;
type ProposalState =
| 'STATE_UNSPECIFIED'
| 'STATE_FAILED'
| 'STATE_OPEN'
| 'STATE_PASSED'
| 'STATE_REJECTED'
| 'STATE_DECLINED'
| 'STATE_ENACTED'
| 'STATE_WAITING_FOR_NODE_VOTE';
type ProposalType =
| 'TYPE_UNSPECIFIED'
| 'TYPE_ALL'
| 'TYPE_NEW_MARKET'
| 'TYPE_UPDATE_MARKET'
| 'TYPE_NETWORK_PARAMETERS'
| 'TYPE_NEW_ASSET'
| 'TYPE_NEW_FREE_FORM'
| 'TYPE_UPDATE_ASSET'
| 'TYPE_NEW_SPOT_MARKET'
| 'TYPE_UPDATE_SPOT_MARKET'
| 'TYPE_NEW_TRANSFER'
| 'TYPE_CANCEL_TRANSFER'
| 'TYPE_UPDATE_MARKET_STATE'
| 'TYPE_UPDATE_REFERRAL_PROGRAM'
| 'TYPE_UPDATE_VOLUME_DISCOUNT_PROGRAM';
type ProposalNodeType = 'TYPE_SINGLE_OR_UNSPECIFIED' | 'TYPE_BATCH';
type ProposalData = {
id: string;
rationale: {
description: string;
title: string;
};
state: ProposalState;
timestamp: string;
};
type Terms = {
cancelTransfer?: { changes: unknown };
enactmentTimestamp: string;
newAsset?: { changes: unknown };
newFreeform: object;
newMarket?: { changes: unknown };
newSpotMarket?: { changes: unknown };
newTransfer?: { changes: unknown };
updateAsset?: { assetId: string; changes: unknown };
updateMarket?: { marketId: string; changes: unknown };
updateMarketState?: {
changes: {
marketId: string;
price: string;
updateType:
| 'MARKET_STATE_UPDATE_TYPE_UNSPECIFIED'
| 'MARKET_STATE_UPDATE_TYPE_TERMINATE'
| 'MARKET_STATE_UPDATE_TYPE_SUSPEND'
| 'MARKET_STATE_UPDATE_TYPE_RESUME';
};
};
updateNetworkParameter?: { changes: unknown };
updateReferralProgram?: { changes: unknown };
updateSpotMarket?: { marketId: string; changes: unknown };
updateVolumeDiscountProgram?: { changes: unknown };
};
export type SingleProposalData = ProposalData & {
terms: Terms & {
closingTimestamp: string;
validationTimestamp: string;
};
};
type BatchProposalData = ProposalData & {
batchTerms: {
changes: Terms[];
};
};
export type SubProposalData = SingleProposalData & {
batchId: string;
};
export type ProposalNode = {
proposal: ProposalData;
proposalType: ProposalNodeType;
proposals: SubProposalData[];
};
type SingleProposalNode = ProposalNode & {
proposal: SingleProposalData;
proposalType: 'TYPE_SINGLE_OR_UNSPECIFIED';
proposals: [];
};
type BatchProposalNode = ProposalNode & {
proposal: BatchProposalData;
proposalType: 'TYPE_BATCH';
};
export const isProposalNode = (node: unknown): node is ProposalNode =>
Boolean(
typeof node === 'object' &&
node &&
'proposal' in node &&
typeof node.proposal === 'object' &&
node?.proposal &&
'id' in node.proposal &&
node?.proposal?.id
);
export const isSingleProposalNode = (
node: Maybe<ProposalNode>
): node is SingleProposalNode =>
Boolean(
node &&
node?.proposalType === 'TYPE_SINGLE_OR_UNSPECIFIED' &&
node?.proposal
);
export const isBatchProposalNode = (
node: Maybe<ProposalNode>
): node is BatchProposalNode =>
Boolean(
node &&
node?.proposalType === 'TYPE_BATCH' &&
node?.proposal &&
'batchTerms' in node.proposal &&
node?.proposals?.length > 0
);
// this includes also batch proposals with `updateMarket`s 👍
const PROPOSALS_ENDPOINT = `${ENV.rest}governances?proposalState=:proposalState&proposalType=:proposalType`;
// this can be queried also by sub proposal id as `proposalId` and it will
// return full batch proposal data with all of its sub proposals including
// the requested one inside `proposals` array.
const PROPOSAL_ENDPOINT = `${ENV.rest}governance?proposalId=:proposalId`;
export const getProposals = async ({
proposalState,
proposalType,
}: {
proposalState: ProposalState;
proposalType: ProposalType;
}) => {
try {
const response = await fetch(
PROPOSALS_ENDPOINT.replace(':proposalState', proposalState).replace(
':proposalType',
proposalType
)
);
if (response.ok) {
const data = await response.json();
if (
data &&
'connection' in data &&
data.connection &&
'edges' in data.connection &&
data.connection.edges?.length > 0
) {
const nodes = compact(
data.connection.edges.map((e: { node?: object }) => e?.node)
).filter(isProposalNode);
return nodes;
}
}
} catch {
// NOOP - ignore errors
}
return [];
};
export const getProposal = async ({ proposalId }: { proposalId: string }) => {
try {
const response = await fetch(
PROPOSAL_ENDPOINT.replace(':proposalId', proposalId)
);
if (response.ok) {
const data = await response.json();
if (data && 'data' in data && isProposalNode(data.data)) {
return data.data as ProposalNode;
}
}
} catch (err) {
// NOOP - ignore errors
}
return null;
};
export const useFetchProposal = ({ proposalId }: { proposalId?: string }) => {
const [data, setData] = useState<ProposalNode | null>(null);
const [loading, setLoading] = useState<boolean>(false);
useEffect(() => {
const cb = async () => {
if (!proposalId) return;
setLoading(true);
const data = await getProposal({ proposalId });
setLoading(false);
if (data) {
setData(data);
}
};
cb();
}, [proposalId]);
return { data, loading };
};
export const useFetchProposals = ({
proposalState,
proposalType,
}: {
proposalState: ProposalState;
proposalType: ProposalType;
}) => {
const [data, setData] = useState<ProposalNode[]>([]);
const [loading, setLoading] = useState<boolean>(false);
useEffect(() => {
const cb = async () => {
setLoading(true);
const data = await getProposals({ proposalState, proposalType });
setLoading(false);
if (data) {
setData(data);
}
};
cb();
}, [proposalState, proposalType]);
return { data, loading };
};
export const flatten = (
nodes: ProposalNode[]
): (SingleProposalData | SubProposalData)[] => {
const flattenNodes = [];
for (const node of nodes) {
if (isSingleProposalNode(node)) {
flattenNodes.push(node.proposal);
}
if (isBatchProposalNode(node)) {
for (const sub of node.proposals) {
flattenNodes.push(sub);
}
}
}
return flattenNodes;
};
@@ -61,7 +61,7 @@ const renderComponent = (proposal: IProposal) => {
<MemoryRouter>
<MockedProvider>
<VegaWalletProvider config={vegaWalletConfig}>
<Proposal restData={{}} proposal={proposal} />
<Proposal restData={null} proposal={proposal} />
</VegaWalletProvider>
</MockedProvider>
</MemoryRouter>
@@ -8,15 +8,17 @@ import { ProposalJson } from '../proposal-json';
import { UserVote } from '../vote-details';
import Routes from '../../../routes';
import { ProposalState } from '@vegaprotocol/types';
import { type ProposalNode } from './proposal-utils';
import { useVoteSubmit } from '@vegaprotocol/proposals';
import { useUserVote } from '../vote-details/use-user-vote';
import { type Proposal as IProposal, type BatchProposal } from '../../types';
import { ProposalChangeDetails } from './proposal-change-details';
import { type JsonValue } from 'type-fest';
export interface ProposalProps {
proposal: IProposal | BatchProposal;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
restData: any;
restData: ProposalNode | null;
}
export const Proposal = ({ proposal, restData }: ProposalProps) => {
@@ -95,7 +97,7 @@ export const Proposal = ({ proposal, restData }: ProposalProps) => {
</div>
<div className="mb-6">
<ProposalJson proposal={restData?.data?.proposal} />
<ProposalJson proposal={restData?.proposal as unknown as JsonValue} />
</div>
</section>
);
@@ -16,6 +16,7 @@ import {
} from '../../__generated__/Proposals';
import { useBatchVoteInformation } from '../../hooks/use-vote-information';
import { getIndicatorStyle } from '../proposal/colours';
import { MarketName } from '../proposal/market-name';
export const CompactVotes = ({ number }: { number: BigNumber }) => (
<CompactNumber
@@ -40,8 +41,9 @@ const VoteProgress = ({
children,
}: VoteProgressProps) => {
const containerClasses = classNames(
'relative h-10 rounded-md border border-vega-dark-300 overflow-hidden',
colourfulBg ? 'bg-vega-pink' : 'bg-vega-dark-400'
'relative h-2 rounded-md overflow-hidden',
// 'border border-vega-dark-300',
colourfulBg ? 'bg-vega-red' : 'bg-vega-dark-200'
);
const progressClasses = classNames(
@@ -50,17 +52,19 @@ const VoteProgress = ({
);
const textClasses = classNames(
'absolute top-0 left-0 w-full h-full flex items-center justify-start px-3 text-black'
'w-full flex items-center justify-start text-white text-sm pb-1'
);
return (
<div className={containerClasses}>
<div
className={progressClasses}
style={{ width: `${percentageFor}%` }}
data-testid={testId}
/>
<div>
<div className={textClasses}>{children}</div>
<div className={containerClasses}>
<div
className={progressClasses}
style={{ width: `${percentageFor}%` }}
data-testid={testId}
/>
</div>
</div>
);
};
@@ -79,14 +83,22 @@ const Status = ({ reached, threshold, text, testId }: StatusProps) => {
<div data-testid={testId}>
{reached ? (
<div className="flex items-center gap-2">
<VegaIcon name={VegaIconNames.TICK} size={20} />
<VegaIcon
name={VegaIconNames.TICK}
className="text-vega-green"
size={20}
/>
<span>
{threshold.toString()}% {text} {t('met')}
</span>
</div>
) : (
<div className="flex items-center gap-2">
<VegaIcon name={VegaIconNames.CROSS} size={20} />
<VegaIcon
name={VegaIconNames.CROSS}
className="text-vega-red"
size={20}
/>
<span>
{threshold.toString()}% {text} {t('not met')}
</span>
@@ -152,7 +164,7 @@ const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => {
<p className="flex gap-2 m-0 items-center">
<VegaIcon
name={VegaIconNames.CROSS}
className="text-vega-pink"
className="text-vega-red"
size={20}
/>
{t(
@@ -215,7 +227,7 @@ const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => {
<p className="flex gap-2 m-0 items-center">
<VegaIcon
name={VegaIconNames.CROSS}
className="text-vega-pink"
className="text-vega-red"
size={20}
/>
{t('Proposal failed: {{count}} of {{total}} proposals passed', {
@@ -237,6 +249,7 @@ const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => {
if (!p?.terms) return null;
return (
<VoteBreakdownBatchSubProposal
indicator={i + 1}
key={i}
proposal={proposal}
votes={proposal.votes}
@@ -273,21 +286,39 @@ const VoteBreakdownBatchSubProposal = ({
const isProposalOpen = proposal?.state === ProposalState.STATE_OPEN;
const isUpdateMarket = terms?.change?.__typename === 'UpdateMarket';
let marketId = undefined;
if (terms?.change?.__typename === 'UpdateMarket') {
marketId = terms.change.marketId;
}
if (terms?.change?.__typename === 'UpdateMarketState') {
marketId = terms.change.market.id;
}
const marketName = marketId ? (
<>
: <MarketName marketId={marketId} />
</>
) : null;
const indicatorElement = indicator && (
<span className={getIndicatorStyle(indicator)}>{indicator}</span>
);
return (
<div>
<div className="flex items-baseline gap-3">
<div className="mb-6">
<div className="flex items-baseline gap-3 mb-3">
{indicatorElement}
<h4>{t(terms.change.__typename)}</h4>
<h4>
{t(terms.change.__typename)} {marketName}
</h4>
</div>
<div className="rounded-sm bg-vega-dark-100 p-3">
<VoteBreakDownUI
voteInfo={voteInfo}
isProposalOpen={isProposalOpen}
isUpdateMarket={isUpdateMarket}
/>
</div>
<VoteBreakDownUI
voteInfo={voteInfo}
isProposalOpen={isProposalOpen}
isUpdateMarket={isUpdateMarket}
/>
</div>
);
};
@@ -302,11 +333,13 @@ const VoteBreakdownNormal = ({ proposal }: { proposal: Proposal }) => {
const isUpdateMarket = proposal?.terms?.change?.__typename === 'UpdateMarket';
return (
<VoteBreakDownUI
voteInfo={voteInfo}
isProposalOpen={isProposalOpen}
isUpdateMarket={isUpdateMarket}
/>
<div className="mb-6">
<VoteBreakDownUI
voteInfo={voteInfo}
isProposalOpen={isProposalOpen}
isUpdateMarket={isUpdateMarket}
/>
</div>
);
};
@@ -370,13 +403,13 @@ const VoteBreakDownUI = ({
'flex justify-between flex-wrap gap-6'
);
const sectionClasses = classNames('min-w-[300px] flex-1 flex-grow');
const headingClasses = classNames('mb-2 text-vega-dark-400');
const headingClasses = classNames('mb-2 text-sm text-white font-bold');
const progressDetailsClasses = classNames(
'flex justify-between flex-wrap mt-2 text-sm'
);
return (
<div className="mb-6">
<div>
{isProposalOpen && (
<div
data-testid="vote-status"
@@ -393,7 +426,7 @@ const VoteBreakDownUI = ({
<VegaIcon
name={VegaIconNames.CROSS}
size={20}
className="text-vega-pink"
className="text-vega-red"
/>
)}
</span>
@@ -409,103 +442,13 @@ const VoteBreakDownUI = ({
<p className="m-0">
<Trans
i18nKey={'Currently expected to <0>fail</0>'}
components={[<span className="text-vega-pink" />]}
components={[<span className="text-vega-red" />]}
/>
</p>
)}
</div>
)}
{isUpdateMarket && (
<div className="mb-4">
<h3 className={headingClasses}>{t('liquidityProviderVote')}</h3>
<div className={sectionWrapperClasses}>
<section
className={sectionClasses}
data-testid="lp-majority-breakdown"
>
<VoteProgress
percentageFor={lpVoteWeight}
colourfulBg={true}
testId="lp-majority-progress"
>
<Status
reached={majorityLPMet}
threshold={requiredMajorityLPPercentage}
text={t('majorityThreshold')}
testId={
majorityLPMet ? 'lp-majority-met' : 'lp-majority-not-met'
}
/>
</VoteProgress>
<div className={progressDetailsClasses}>
<div className="flex items-center gap-1">
<span>{t('liquidityProviderVotesFor')}:</span>
<Tooltip
description={
<span>{lpVoteWeight.toFixed(defaultDP)}%</span>
}
>
<button>{lpVoteWeight.toFixed(1)}%</button>
</Tooltip>
</div>
<div className="flex items-center gap-1">
<span>{t('liquidityProviderVotesAgainst')}:</span>
<span>
<Tooltip
description={
<span>{noLPPercentage.toFixed(defaultDP)}%</span>
}
>
<button>{noLPPercentage.toFixed(1)}%</button>
</Tooltip>
</span>
</div>
</div>
</section>
<section
className={sectionClasses}
data-testid="lp-participation-breakdown"
>
<VoteProgress
percentageFor={
lpParticipationThresholdProgress || new BigNumber(0)
}
testId="lp-participation-progress"
>
<Status
reached={participationLPMet}
threshold={requiredParticipationLP || new BigNumber(1)}
text={t('participationThreshold')}
testId={
participationLPMet
? 'lp-participation-met'
: 'lp-participation-not-met'
}
/>
</VoteProgress>
<div className="flex mt-2 text-sm">
<div className="flex items-center gap-1">
<span>{t('totalLiquidityProviderTokensVoted')}:</span>
<Tooltip
description={formatNumber(
totalEquityLikeShareWeight,
defaultDP
)}
>
<span>{totalEquityLikeShareWeight.toFixed(1)}%</span>
</Tooltip>
</div>
</div>
</section>
</div>
</div>
)}
{isUpdateMarket && <h3 className={headingClasses}>{t('tokenVote')}</h3>}
<div className={sectionWrapperClasses}>
<section
@@ -605,6 +548,97 @@ const VoteBreakDownUI = ({
</div>
</section>
</div>
{/** Liquidity provider vote */}
{isUpdateMarket && (
<div className="mt-3">
<h3 className={headingClasses}>{t('liquidityProviderVote')}</h3>
<div className={sectionWrapperClasses}>
<section
className={sectionClasses}
data-testid="lp-majority-breakdown"
>
<VoteProgress
percentageFor={lpVoteWeight}
colourfulBg={true}
testId="lp-majority-progress"
>
<Status
reached={majorityLPMet}
threshold={requiredMajorityLPPercentage}
text={t('majorityThreshold')}
testId={
majorityLPMet ? 'lp-majority-met' : 'lp-majority-not-met'
}
/>
</VoteProgress>
<div className={progressDetailsClasses}>
<div className="flex items-center gap-1">
<span>{t('liquidityProviderVotesFor')}:</span>
<Tooltip
description={
<span>{lpVoteWeight.toFixed(defaultDP)}%</span>
}
>
<button>{lpVoteWeight.toFixed(1)}%</button>
</Tooltip>
</div>
<div className="flex items-center gap-1">
<span>{t('liquidityProviderVotesAgainst')}:</span>
<span>
<Tooltip
description={
<span>{noLPPercentage.toFixed(defaultDP)}%</span>
}
>
<button>{noLPPercentage.toFixed(1)}%</button>
</Tooltip>
</span>
</div>
</div>
</section>
<section
className={sectionClasses}
data-testid="lp-participation-breakdown"
>
<VoteProgress
percentageFor={
lpParticipationThresholdProgress || new BigNumber(0)
}
testId="lp-participation-progress"
>
<Status
reached={participationLPMet}
threshold={requiredParticipationLP || new BigNumber(1)}
text={t('participationThreshold')}
testId={
participationLPMet
? 'lp-participation-met'
: 'lp-participation-not-met'
}
/>
</VoteProgress>
<div className="flex mt-2 text-sm">
<div className="flex items-center gap-1">
<span>{t('totalLiquidityProviderTokensVoted')}:</span>
<Tooltip
description={formatNumber(
totalEquityLikeShareWeight,
defaultDP
)}
>
<span>{totalEquityLikeShareWeight.toFixed(1)}%</span>
</Tooltip>
</div>
</div>
</section>
</div>
</div>
)}
</div>
);
};
@@ -1,17 +1,16 @@
import { useParams } from 'react-router-dom';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { useFetch } from '@vegaprotocol/react-helpers';
import { ENV } from '../../../config';
import { Proposal } from '../components/proposal';
import { ProposalNotFound } from '../components/proposal-not-found';
import { useProposalQuery } from '../__generated__/Proposals';
import { useFetchProposal } from '../components/proposal/proposal-utils';
export const ProposalContainer = () => {
const params = useParams<{ proposalId: string }>();
const {
state: { data: restData, loading: restLoading, error: restError },
} = useFetch(`${ENV.rest}governance?proposalId=${params.proposalId}`);
const { data: restData, loading: restLoading } = useFetchProposal({
proposalId: params.proposalId,
});
const { data, loading, error } = useProposalQuery({
fetchPolicy: 'network-only',
@@ -26,7 +25,7 @@ export const ProposalContainer = () => {
return (
<AsyncRenderer
loading={Boolean(loading || restLoading)}
error={error || restError}
error={error}
data={{
...data,
...(restData ? { restData } : {}),
@@ -4,7 +4,6 @@ import {
lpAggregatedDataProvider,
type Filter,
LiquidityTable,
liquidityProvisionsDataProvider,
} from '@vegaprotocol/liquidity';
import { getAsset, useMarket } from '@vegaprotocol/markets';
import {
@@ -71,7 +70,7 @@ export const LiquidityContainer = ({
const useReloadLiquidityData = (marketId: string | undefined) => {
const { reload } = useDataProvider({
dataProvider: liquidityProvisionsDataProvider,
dataProvider: lpAggregatedDataProvider,
variables: { marketId: marketId || '' },
update: () => true,
skip: !marketId,
+1 -1
View File
@@ -1,3 +1,3 @@
CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest
VEGA_VERSION=v0.74.1
VEGA_VERSION=v0.74.3
LOCAL_SERVER=false
+1 -1
View File
@@ -1,3 +1,3 @@
CONSOLE_IMAGE_NAME=vegaprotocol/trading:develop
VEGA_VERSION=v0.74.1
VEGA_VERSION=v0.74.3
LOCAL_SERVER=false
+63 -119
View File
@@ -1,156 +1,100 @@
# Trading Market-Sim End-To-End Tests
This direcotry contains end-to-end tests for the trading application using vega-market-sim. This README will guide you through setting up your environment and running the tests.
This directory contains end-to-end tests for the Trading application using Vega-market-sim. This guide will help you set up your environment and run the tests efficiently.
## Prerequisites
- [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
- [Docker](https://www.docker.com/)
- [Python versions ">=3.9,<3.11"](https://www.python.org/)
Ensure you have the following installed:
## Getting Started
- [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer) for dependency management.
- [Docker](https://www.docker.com/) for running isolated application containers.
- Python, versions ">=3.9,<3.11". Install from the [official Python website](https://www.python.org/).
1. **Install Poetry**: Follow the instructions on the [official Poetry website](https://python-poetry.org/docs/#installing-with-the-official-installer).
2. **Install Docker**: Follow the instructions on the [official Docker website](https://docs.docker.com/desktop/).
3. **Install Python**: Follow the instructions on the [official Python website](https://www.python.org/)
**ensure you install a version between 3.9 and 3.11.**
4. **Start up a Poetry environment**: Execute the commands below to configure the Poetry environment.
## Setup
### Ensure you are in the tests folder before running commands
### 1. Install Dependencies
- **Poetry**: Follow the installation guide on the [official Poetry website](https://python-poetry.org/docs/#installing-with-the-official-installer).
- **Docker**: Installation instructions are available on the [official Docker website](https://docs.docker.com/desktop/).
- **Python**: Install a version between 3.9 and 3.11, as detailed on the [official Python website](https://www.python.org/).
### 2. Configure Your Environment
Ensure you're in the tests folder before executing commands.
```bash
poetry shell
```
5. **Install python dependencies**
To make sure you are on the latest version of our market-sim branch.
```bash
poetry update vega-sim
```
```bash
poetry update vega-sim # Updates to the latest version of the market-sim branch
poetry install
playwright install chromium # Installs necessary browsers for Playwright
```
6. **Install Playwright Browsers**: Execute the command below to browsers for Playwright.
### 3. Prepare Binaries and Docker Images
```bash
playwright install chromium
```
7. **Download necessary binaries**:
Use the following command within your Python environment. The `--force` flag ensures the binaries are overwritten, and the `--version` specifies the desired version. e.g. `v0.73.4`
Download necessary binaries for the desired Vega version:
```bash
python -m vega_sim.tools.load_binaries --force --version $VEGA_VERSION
```
8. **Pull the desired Docker image**
Pull Docker images for your environment:
```bash
docker pull vegaprotocol/trading:develop
```
- **Development**: `docker pull vegaprotocol/trading:develop`
- **Production**: `docker pull vegaprotocol/trading:main`
9. **Run tests**: Poetry/Python will serve the app from docker
### Update the .env file with the correct trading image.
```bash
poetry run pytest
```
### Docker images
Pull the desired image:
**Testnet**
```bash
docker pull vegaprotocol/trading:develop
```
**Mainnet**
```bash
docker pull vegaprotocol/trading:main
```
Find all available images on [Docker Hub](https://hub.docker.com/r/vegaprotocol/trading/tags).
#### Create a Docker Image of Your Locally Built Trading App
To build your Docker image, use the following commands:
```bash
yarn nx build trading ./docker/prepare-dist.sh
```
### 4. Build a Docker Image of Your Locally Built Trading App
```bash
./docker/prepare-dist.sh
docker build -f docker/node-outside-docker.Dockerfile --build-arg APP=trading --build-arg ENV_NAME=stagnet1 -t vegaprotocol/trading:latest .
```
## Running Tests 🧪
## Running Tests
Before running make sure the docker daemon is running.
Ensure the Docker daemon is running. Update the `.env` file with the correct trading image before proceeding.
To run a specific test, use the `-k` option followed by the name of the test.
Run all tests:
- **Run all tests**: `poetry run pytest`
- **Run a specific test**: `poetry run pytest -k "test_name" -s --headed`
- **Run tests using your locally served console**:
```bash
poetry run pytest
In one terminal window, build and serve the trading console:
```bash
yarn nx build trading
yarn nx serve trading
```
Once the console is served, update the `.env` file to set `local_server=true`. You can then run your tests using the same commands as above.
NOTE: Parallel running of tests will not work against locally served console.
## Test Strategy and Container Cleanup
### Strategy
We aim for each test file to use a single Vega instance to ensure test isolation and manage resources efficiently. This approach helps in maintaining test performance and reliability.
### Cleanup Procedure
To ensure proper cleanup of containers after each test, use the following fixture pattern:
```python
@pytest.fixture
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
```
Run a targeted test:
## Running Tests in Parallel
```bash
poetry run pytest -k "test_name" -s --headed
```
For running tests in parallel:
Run from anywhere:
- **Within the e2e folder**: `poetry run pytest -s --numprocesses auto --dist loadfile`
- **From anywhere**: `yarn trading:test:all`
```bash
yarn trading:test -- "test_name" -s --headed
```
## Troubleshooting
Run using your locally served console:
If IntelliSense is not working in VSCode, follow these steps:
Within one terminal
```bash
yarn nx build trading
```
```bash
yarn nx serve trading
```
Once console is served you can update the .env file to have local_server to true.
## Running Tests in Parallel 🔢
To run tests in parallel, use the `--numprocesses auto` option. The `--dist loadfile` setting ensures that multiple runners are not assigned to a single test file.
### From within the e2e folder:
```bash
poetry run pytest -s --numprocesses auto --dist loadfile
```
### From anywhere:
```bash
yarn trading:test:all
```
# Things to know
If you "intellisense" isn't working follow these steps:
1. ```bash
poetry run which python
```
2. Then open the command menu in vscode (cmd + shift + p) and type `select interpreter` , press enter, select enter interpreter path press enter then paste in the output from that above command you should get the right python again
1. Find the Poetry environment's Python binary: `poetry run which python`
2. In VSCode, open the command menu (`cmd + shift + p`), search for `Python: Select Interpreter`, select `Enter interpreter path`, and paste the path from step 1.
+394 -390
View File
File diff suppressed because it is too large Load Diff
@@ -235,7 +235,7 @@ def test_submit_stop_oco_market_order_pending(
"PendingOCO"
)
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_oco_limit_order_pending(
continuous_market, vega: VegaServiceNull, page: Page
):
@@ -0,0 +1,60 @@
# test_ids.py
# Constants for test IDs
ADJUSTED_FEES = "adjusted-fees"
TOTAL_FEE_BEFORE_DISCOUNT = "total-fee-before-discount"
INFRASTRUCTURE_FEES = "infrastructure-fees"
MAKER_FEES = "maker-fees"
LIQUIDITY_FEES = "liquidity-fees"
TOTAL_DISCOUNT = "total-discount"
VOLUME_DISCOUNT_ROW = "volume-discount-row"
REFERRAL_DISCOUNT_ROW = "referral-discount-row"
PAST_EPOCHS_VOLUME = "past-epochs-volume"
REQUIRED_FOR_NEXT_TIER = "required-for-next-tier"
TIER_VALUE_0 = "tier-value-0"
TIER_VALUE_1 = "tier-value-1"
DISCOUNT_VALUE_0 = "discount-value-0"
DISCOUNT_VALUE_1 = "discount-value-1"
MIN_VOLUME_VALUE_0 = "min-volume-value-0"
MIN_VOLUME_VALUE_1 = "min-volume-value-1"
MY_VOLUME_VALUE_0 = "my-volume-value-0"
MY_VOLUME_VALUE_1 = "my-volume-value-1"
ORDER_SIZE = "order-size"
ORDER_PRICE = "order-price"
DISCOUNT_PILL = "discount-pill"
FEES_TEXT = "fees-text"
TOOLTIP_CONTENT = "tooltip-content"
INFRASTRUCTURE_FEE_FACTOR = "infrastructure-fee-factor"
INFRASTRUCTURE_FEE_VALUE = "infrastructure-fee-value"
LIQUIDITY_FEE_FACTOR = "liquidity-fee-factor"
LIQUIDITY_FEE_VALUE = "liquidity-fee-value"
MAKER_FEE_FACTOR = "maker-fee-factor"
MAKER_FEE_VALUE = "maker-fee-value"
SUBTOTAL_FEE_FACTOR = "subtotal-fee-factor"
SUBTOTAL_FEE_VALUE = "subtotal-fee-value"
DISCOUNT_FEE_FACTOR = "discount-fee-factor"
DISCOUNT_FEE_VALUE = "discount-fee-value"
TOTAL_FEE_VALUE = "total-fee-value"
RUNNING_NOTIONAL_TAKER_VOLUME = "running-notional-taker-volume"
EPOCHS_IN_REFERRAL_SET = "epochs-in-referral-set"
REQUIRED_EPOCHS_VALUE_0 = "required-epochs-value-0"
REQUIRED_EPOCHS_VALUE_1 = "required-epochs-value-1"
FILLS = "Fills"
TAB_FILLS = "tab-fills"
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 = '[data-testid="market-code"]'
COL_CODE = '[col-id="code"]'
COL_SIZE = '[col-id="size"]'
COL_PRICE = '[col-id="price"]'
COL_PRICE_1 = '[col-id="price_1"]'
COL_AGGRESSOR = '[col-id="aggressor"]'
COL_FEE = '[col-id="fee"]'
COL_FEE_DISCOUNT = '[col-id="fee-discount"]'
COL_FEE_AFTER_DISCOUNT = '[col-id="feeAfterDiscount"]'
COL_INFRA_FEE = '[col-id="infraFee"]'
COL_MAKER_FEE = '[col-id="makerFee"]'
COL_LIQUIDITY_FEE = '[col-id="liquidityFee"]'
COL_TOTAL_FEE = '[col-id="totalFee"]'
-689
View File
@@ -1,689 +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 wallet_config import MM_WALLET
from conftest import init_vega, init_page, auth_setup, cleanup_container
from actions.utils import next_epoch, change_keys, forward_time
from fixtures.market import market_exists, setup_continuous_market
# region Constants for test IDs
ADJUSTED_FEES = "adjusted-fees"
TOTAL_FEE_BEFORE_DISCOUNT = "total-fee-before-discount"
INFRASTRUCTURE_FEES = "infrastructure-fees"
MAKER_FEES = "maker-fees"
LIQUIDITY_FEES = "liquidity-fees"
TOTAL_DISCOUNT = "total-discount"
VOLUME_DISCOUNT_ROW = "volume-discount-row"
REFERRAL_DISCOUNT_ROW = "referral-discount-row"
PAST_EPOCHS_VOLUME = "past-epochs-volume"
REQUIRED_FOR_NEXT_TIER = "required-for-next-tier"
TIER_VALUE_0 = "tier-value-0"
TIER_VALUE_1 = "tier-value-1"
DISCOUNT_VALUE_0 = "discount-value-0"
DISCOUNT_VALUE_1 = "discount-value-1"
MIN_VOLUME_VALUE_0 = "min-volume-value-0"
MIN_VOLUME_VALUE_1 = "min-volume-value-1"
MY_VOLUME_VALUE_0 = "my-volume-value-0"
MY_VOLUME_VALUE_1 = "my-volume-value-1"
ORDER_SIZE = "order-size"
ORDER_PRICE = "order-price"
DISCOUNT_PILL = "discount-pill"
FEES_TEXT = "fees-text"
TOOLTIP_CONTENT = "tooltip-content"
INFRASTRUCTURE_FEE_FACTOR = "infrastructure-fee-factor"
INFRASTRUCTURE_FEE_VALUE = "infrastructure-fee-value"
LIQUIDITY_FEE_FACTOR = "liquidity-fee-factor"
LIQUIDITY_FEE_VALUE = "liquidity-fee-value"
MAKER_FEE_FACTOR = "maker-fee-factor"
MAKER_FEE_VALUE = "maker-fee-value"
SUBTOTAL_FEE_FACTOR = "subtotal-fee-factor"
SUBTOTAL_FEE_VALUE = "subtotal-fee-value"
DISCOUNT_FEE_FACTOR = "discount-fee-factor"
DISCOUNT_FEE_VALUE = "discount-fee-value"
TOTAL_FEE_VALUE = "total-fee-value"
RUNNING_NOTIONAL_TAKER_VOLUME = "running-notional-taker-volume"
EPOCHS_IN_REFERRAL_SET = "epochs-in-referral-set"
REQUIRED_EPOCHS_VALUE_0 = "required-epochs-value-0"
REQUIRED_EPOCHS_VALUE_1 = "required-epochs-value-1"
FILLS = "Fills"
TAB_FILLS = "tab-fills"
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 = '[data-testid="market-code"]'
COL_CODE = '[col-id="code"]'
COL_SIZE = '[col-id="size"]'
COL_PRICE = '[col-id="price"]'
COL_PRICE_1 = '[col-id="price_1"]'
COL_AGGRESSOR = '[col-id="aggressor"]'
COL_FEE = '[col-id="fee"]'
COL_FEE_DISCOUNT = '[col-id="fee-discount"]'
COL_FEE_AFTER_DISCOUNT = '[col-id="feeAfterDiscount"]'
COL_INFRA_FEE = '[col-id="infraFee"]'
COL_MAKER_FEE = '[col-id="makerFee"]'
COL_LIQUIDITY_FEE = '[col-id="liquidityFee"]'
COL_TOTAL_FEE = '[col-id="totalFee"]'
# endregion
@pytest.fixture(scope="module")
def market_ids():
return {
"tier_1_volume": "default_id",
"tier_2_volume": "default_id",
"tier_1_referral": "default_id",
"tier_2_referral": "default_id",
"combo": "default_id",
}
@pytest.fixture(scope="module")
def vega_volume_discount_tier_1(request):
with init_vega(request) as vega_volume_discount_tier_1:
request.addfinalizer(lambda: cleanup_container(vega_volume_discount_tier_1)) # Register the cleanup function
yield vega_volume_discount_tier_1
@pytest.fixture(scope="module")
def vega_volume_discount_tier_2(request):
with init_vega(request) as vega_volume_discount_tier_2:
request.addfinalizer(lambda: cleanup_container(vega_volume_discount_tier_2)) # Register the cleanup function
yield vega_volume_discount_tier_2
@pytest.fixture(scope="module")
def vega_referral_discount_tier_1(request):
with init_vega(request) as vega_referral_discount_tier_1:
request.addfinalizer(lambda: cleanup_container(vega_referral_discount_tier_1)) # Register the cleanup function
yield vega_referral_discount_tier_1
@pytest.fixture(scope="module")
def vega_referral_discount_tier_2(request):
with init_vega(request) as vega_referral_discount_tier_2:
request.addfinalizer(lambda: cleanup_container(vega_referral_discount_tier_2)) # Register the cleanup function
yield vega_referral_discount_tier_2
@pytest.fixture(scope="module")
def vega_referral_and_volume_discount(request):
with init_vega(request) as vega_referral_and_volume_discount:
request.addfinalizer(lambda: cleanup_container(vega_referral_and_volume_discount)) # Register the cleanup function
yield vega_referral_and_volume_discount
@pytest.fixture
def page(vega_instance, browser, request):
with init_page(vega_instance, browser, request) as page_instance:
yield page_instance
@pytest.fixture
def vega_instance(
tier,
discount_program,
vega_volume_discount_tier_1,
vega_volume_discount_tier_2,
vega_referral_discount_tier_1,
vega_referral_discount_tier_2,
vega_referral_and_volume_discount,
):
if discount_program == "volume":
return vega_volume_discount_tier_1 if tier == 1 else vega_volume_discount_tier_2
elif discount_program == "referral":
return (
vega_referral_discount_tier_1
if tier == 1
else vega_referral_discount_tier_2
)
elif discount_program == "combo":
return vega_referral_and_volume_discount
@pytest.fixture
def auth(vega_instance, page):
return auth_setup(vega_instance, page)
def setup_market_with_volume_discount_program(vega: VegaServiceNull, tier: int):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
order_count = 2 if tier == 1 else 3
for _ in range(order_count):
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega, True if _ < order_count - 1 else False)
return market
def setup_market_with_referral_discount_program(vega: VegaServiceNull, tier: int):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
order_count = 2
order_size = 1 if tier == 1 else 2
for _ in range(order_count):
submit_order(vega, "Key 1", market, "SIDE_BUY", order_size, 110)
forward_time(vega, True if _ < order_count - 1 else False)
return market
def setup_combined_market(vega: VegaServiceNull):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
order_count = 2
order_size = 2
for _ in range(order_count):
submit_order(vega, "Key 1", market, "SIDE_BUY", order_size, 110)
forward_time(vega, True if _ < order_count - 1 else False)
return market
def set_market_volume_discount(vega, tier, discount_program, market_ids):
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key, "default_id")
print(f"Checking if market exists: {market_id}")
if not market_exists(vega, market_id):
print(
f"Market doesn't exist for {discount_program} tier {tier}. Setting up new market."
)
if discount_program == "volume":
market_id = setup_market_with_volume_discount_program(vega, tier)
elif discount_program == "referral":
market_id = setup_market_with_referral_discount_program(vega, tier)
elif discount_program == "combo":
market_id = setup_combined_market(vega)
market_ids[market_id_key] = market_id
print(f"Using market ID: {market_id}")
return market_ids
@pytest.mark.parametrize(
"tier, discount_program, expected_text",
[
(1, "volume", "9.045%-9.045%"),
(2, "volume", "8.04%-8.04%"),
(1, "referral", "9.045%-9.045%"),
(2, "referral", "8.04%-8.04%"),
(2, "combo", "6.432%-6.432%"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_my_trading_fees(
tier, expected_text, discount_program, vega_instance, page: Page, market_ids
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text(expected_text)
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
"Total fee before discount10.05%-10.05%"
)
expect(page.get_by_test_id(INFRASTRUCTURE_FEES)).to_have_text("Infrastructure0.05%")
expect(page.get_by_test_id(MAKER_FEES)).to_have_text("Maker10%")
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
@pytest.mark.parametrize(
"tier, discount_program, volume_discount, total_discount, referral_discount",
[
(1, "volume", "Volume discount10%", "10%", "Referral discount0%"),
(2, "volume", "Volume discount20%", "20%", "Referral discount0%"),
(1, "referral", "Volume discount0%", "10%", "Referral discount10%"),
(2, "referral", "Volume discount0%", "20%", "Referral discount20%"),
(2, "combo", "Volume discount20%", "36%", "Referral discount20%"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_total_discount(
tier,
discount_program,
volume_discount,
referral_discount,
total_discount,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text(total_discount)
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text(volume_discount)
expect(page.get_by_test_id(REFERRAL_DISCOUNT_ROW)).to_have_text(referral_discount)
page.get_by_test_id(TOTAL_DISCOUNT).hover()
expect(page.get_by_test_id(TOOLTIP_CONTENT).nth(0)).to_have_text(
"The total discount is calculated according to the following formula: 1 - (1 - dvolume) ⋇ (1 - dreferral)"
)
@pytest.mark.parametrize(
"tier, discount_program, past_epochs_volume, required_for_next_tier",
[(1, "volume", "103", "97"), (2, "volume", "206", "")],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_volume_discount_program_my_current_volume(
tier,
discount_program,
past_epochs_volume,
required_for_next_tier,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(PAST_EPOCHS_VOLUME)).to_have_text(past_epochs_volume)
if tier == 1:
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).to_have_text(
required_for_next_tier
)
else:
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).not_to_be_visible()
@pytest.mark.parametrize(
"tier, discount_program, notional_taker_volume, epochs_in_set",
[(1, "referral", "103", "1"), (2, "referral", "207", "1")],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_referral_discount_program_referral_benefits(
tier,
vega_instance,
discount_program,
notional_taker_volume,
epochs_in_set,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(RUNNING_NOTIONAL_TAKER_VOLUME)).to_have_text(
notional_taker_volume
)
expect(page.get_by_test_id(EPOCHS_IN_REFERRAL_SET)).to_have_text(epochs_in_set)
@pytest.mark.parametrize(
"tier, discount_program, my_volume_test_id, my_volume_value, your_tier",
[
(1, "volume", "my-volume-value-0", "103", "your-volume-tier-0"),
(2, "volume", "my-volume-value-1", "206", "your-volume-tier-1"),
(1, "referral", "my-volume-value-0", "103", "your-referral-tier-0"),
(2, "referral", "my-volume-value-1", "206", "your-referral-tier-1"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_discount(
tier,
discount_program,
my_volume_test_id,
my_volume_value,
your_tier,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id(DISCOUNT_VALUE_0)).to_have_text("10%")
expect(page.get_by_test_id(DISCOUNT_VALUE_1)).to_have_text("20%")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_0)).to_have_text("100")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_1)).to_have_text("200")
if discount_program == "volume":
expect(page.get_by_test_id(my_volume_test_id)).to_have_text(my_volume_value)
else:
expect(page.get_by_test_id(REQUIRED_EPOCHS_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(REQUIRED_EPOCHS_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id(your_tier).nth(1)).to_be_visible()
expect(page.get_by_test_id(your_tier).nth(1)).to_have_text("Your tier")
@pytest.mark.parametrize(
"tier, discount_program, fees_after_discount",
[
(1, "volume", "9.045%"),
(2, "volume", "8.04%"),
(1, "referral", "9.045%"),
(2, "referral", "8.04%"),
(2, "combo", "6.432%"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_fees_by_market(
tier, discount_program, fees_after_discount, vega_instance, page: Page, market_ids
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
pinned = page.locator(PINNED_ROW_LOCATOR)
row = page.locator(ROW_LOCATOR)
expect(pinned.locator(COL_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_FEE_AFTER_DISCOUNT)).to_have_text(fees_after_discount)
expect(row.locator(COL_INFRA_FEE)).to_have_text("0.05%")
expect(row.locator(COL_MAKER_FEE)).to_have_text("10%")
expect(row.locator(COL_LIQUIDITY_FEE)).to_have_text("0%")
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.parametrize(
"tier, discount_program, discount, discount_value, total_fee",
[
(1, "volume", "-10%", "-0.01005 tDAI", "0.09045 tDAI"),
(2, "volume", "-20%", "-0.0201 tDAI", "0.0804 tDAI"),
(1, "referral", "-10%", "-0.01005 tDAI", "0.09045 tDAI"),
(2, "referral", "-20%", "-0.0201 tDAI", "0.0804 tDAI"),
(2, "combo", "-36%", "-0.03618 tDAI", "0.06432 tDAI"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_deal_ticket_discount_program(
tier,
discount_program,
discount,
discount_value,
total_fee,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text(discount)
page.get_by_test_id(FEES_TEXT).hover()
tooltip = page.get_by_test_id(TOOLTIP_CONTENT).first
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_FACTOR)).to_have_text("0.05%")
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_VALUE)).to_have_text("0.0005 tDAI")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_FACTOR)).to_have_text("0%")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_VALUE)).to_have_text("0.00 tDAI")
expect(tooltip.get_by_test_id(MAKER_FEE_FACTOR)).to_have_text("10%")
expect(tooltip.get_by_test_id(MAKER_FEE_VALUE)).to_have_text("0.10 tDAI")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_FACTOR)).to_have_text("10.05%")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_VALUE)).to_have_text("0.1005 tDAI")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_FACTOR)).to_have_text(discount)
expect(tooltip.get_by_test_id(DISCOUNT_FEE_VALUE)).to_have_text(discount_value)
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text(total_fee)
@pytest.mark.parametrize(
"tier, discount_program, fee, fee_discount, price_1, size",
[
(1, "volume", "9.36158 tDAI", "1.04017 tDAI", "103.50 tDAI", "+1"),
(2, "volume", "8.3214 tDAI", "2.08035 tDAI", "103.50 tDAI", "+1"),
(
1,
"referral",
"8.42543 tDAI ",
"1.04017 tDAI",
"103.50 tDAI",
"+1",
),
(
2,
"referral",
"13.31424 tDAI",
"4.1607 tDAI",
"207.00 tDAI",
"+2",
),
(2, "combo", "10.6514 tDAI ", "7.48926 tDAI", "207.00 tDAI", "+2"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_taker_discount_program(
tier,
discount_program,
fee,
fee_discount,
price_1,
size,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
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_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)
expect(row.locator(COL_AGGRESSOR)).to_have_text("Taker")
expect(row.locator(COL_FEE)).to_have_text(fee)
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text(fee_discount)
@pytest.mark.parametrize(
"tier, discount_program, fee, fee_discount, size, price_1",
[
(1, "volume", "-9.315 tDAI", "1.035 tDAI", "-1", "103.50 tDAI"),
(2, "volume", "-8.28 tDAI", "2.07 tDAI", "-1", "103.50 tDAI"),
(1, "referral", "-8.3835 tDAI", "1.035 tDAI", "-1", "103.50 tDAI"),
(2, "referral", "-13.248 tDAI", "4.14 tDAI", "-2", "207.00 tDAI"),
(2, "combo", "-10.5984 tDAI ", "7.452 tDAI", "-2", "207.00 tDAI"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_maker_discount_program(
tier,
discount_program,
vega_instance,
fee,
fee_discount,
size,
price_1,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
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_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)
expect(row.locator(COL_AGGRESSOR)).to_have_text("Maker")
expect(row.locator(COL_FEE)).to_have_text(fee)
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text(fee_discount)
@pytest.mark.parametrize(
"tier, discount_program, fee",
[
(1, "volume", "9.315"),
(2, "volume", "8.28"),
(1, "referral", "8.3835"),
(2, "referral", "13.248"),
(2, "combo", "10.5984"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_maker_fee_tooltip_discount_program(
tier, discount_program, fee, vega_instance, page: Page, market_ids
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
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
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
f"If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-{fee} tDAITotal fees-{fee} tDAI"
)
@pytest.mark.parametrize(
"tier, discount_program, maker_fee, total_fee, infra_fee",
[
(1, "volume", "9.315", "9.36158", "0.04658"),
(2, "volume", "8.28", "8.3214", "0.0414"),
(1, "referral", "8.3835", "8.42543", "0.04193"),
(2, "referral", "13.248", "13.31424", "0.06624"),
(2, "combo", "10.5984", "10.6514", "0.053"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_taker_fee_tooltip_discount_program(
tier,
discount_program,
vega_instance,
maker_fee,
total_fee,
infra_fee,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
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
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
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"
)
@@ -0,0 +1,216 @@
import pytest
from fees_test_ids import *
from playwright.sync_api import Page, expect
from vega_sim.null_service import VegaServiceNull
from actions.vega import submit_order
from wallet_config import MM_WALLET
from conftest import (
init_vega,
init_page,
auth_setup,
risk_accepted_setup,
cleanup_container,
)
from actions.utils import next_epoch, change_keys, forward_time
from fixtures.market import setup_continuous_market
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(
lambda: cleanup_container(vega_instance)
)
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_combined_market(vega: VegaServiceNull):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
for _ in range(2):
submit_order(vega, "Key 1", market, "SIDE_BUY", 2, 110)
forward_time(vega, True if _ < 2 - 1 else False)
return market
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fees_page_discount_program_my_trading_fees(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("6.432%-6.432%")
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
"Total fee before discount10.05%-10.05%"
)
expect(page.get_by_test_id(INFRASTRUCTURE_FEES)).to_have_text("Infrastructure0.05%")
expect(page.get_by_test_id(MAKER_FEES)).to_have_text("Maker10%")
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fees_page_discount_program_total_discount(
page: Page,
):
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("36%")
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount20%")
expect(page.get_by_test_id(REFERRAL_DISCOUNT_ROW)).to_have_text(
"Referral discount20%"
)
page.get_by_test_id(TOTAL_DISCOUNT).hover()
expect(page.get_by_test_id(TOOLTIP_CONTENT).nth(0)).to_have_text(
"The total discount is calculated according to the following formula: 1 - (1 - dvolume) ⋇ (1 - dreferral)"
)
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fees_page_discount_program_fees_by_market(page: Page):
page.goto("/#/fees")
pinned = page.locator(PINNED_ROW_LOCATOR)
row = page.locator(ROW_LOCATOR)
expect(pinned.locator(COL_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_FEE_AFTER_DISCOUNT)).to_have_text("6.432%")
expect(row.locator(COL_INFRA_FEE)).to_have_text("0.05%")
expect(row.locator(COL_MAKER_FEE)).to_have_text("10%")
expect(row.locator(COL_LIQUIDITY_FEE)).to_have_text("0%")
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_deal_ticket_discount_program(
page: Page,
setup_combined_market,
):
page.goto(f"/#/markets/{setup_combined_market}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-36%")
page.get_by_test_id(FEES_TEXT).hover()
tooltip = page.get_by_test_id(TOOLTIP_CONTENT).first
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_FACTOR)).to_have_text("0.05%")
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_VALUE)).to_have_text("0.0005 tDAI")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_FACTOR)).to_have_text("0%")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_VALUE)).to_have_text("0.00 tDAI")
expect(tooltip.get_by_test_id(MAKER_FEE_FACTOR)).to_have_text("10%")
expect(tooltip.get_by_test_id(MAKER_FEE_VALUE)).to_have_text("0.10 tDAI")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_FACTOR)).to_have_text("10.05%")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_VALUE)).to_have_text("0.1005 tDAI")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_FACTOR)).to_have_text("-36%")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_VALUE)).to_have_text("-0.03618 tDAI")
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.06432 tDAI")
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fills_taker_discount_program(
page: Page,
setup_combined_market,
):
page.goto(f"/#/markets/{setup_combined_market}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_SIZE)).to_have_text("+2")
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text("207.00 tDAI")
expect(row.locator(COL_AGGRESSOR)).to_have_text("Taker")
expect(row.locator(COL_FEE)).to_have_text("10.6514 tDAI")
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("7.48926 tDAI")
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fills_maker_discount_program(
vega: VegaServiceNull,
page: Page,
setup_combined_market,
):
page.goto(f"/#/markets/{setup_combined_market}")
change_keys(page, vega, 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_SIZE)).to_have_text("-2")
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text("207.00 tDAI")
expect(row.locator(COL_AGGRESSOR)).to_have_text("Maker")
expect(row.locator(COL_FEE)).to_have_text("-10.5984 tDAI")
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("7.452 tDAI")
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fills_maker_fee_tooltip_discount_program(
vega: VegaServiceNull, page: Page, setup_combined_market
):
page.goto(f"/#/markets/{setup_combined_market}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
"If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-10.5984 tDAITotal fees-10.5984 tDAI"
)
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fills_taker_fee_tooltip_discount_program(
page: Page,
setup_combined_market,
):
page.goto(f"/#/markets/{setup_combined_market}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
"If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-10.5984 tDAITotal fees-10.5984 tDAI"
)
@@ -0,0 +1,221 @@
import pytest
from fees_test_ids import *
from playwright.sync_api import Page, expect
from vega_sim.null_service import VegaServiceNull
from actions.vega import submit_order
from wallet_config import MM_WALLET
from conftest import (
init_vega,
init_page,
auth_setup,
risk_accepted_setup,
cleanup_container,
)
from actions.utils import next_epoch, change_keys, forward_time
from fixtures.market import setup_continuous_market
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(
lambda: cleanup_container(vega_instance)
)
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_referral_discount_program(vega: VegaServiceNull):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
for _ in range(2):
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega, True if _ < 2 - 1 else False)
return market
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fees_page_discount_program_my_trading_fees(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("9.045%-9.045%")
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
"Total fee before discount10.05%-10.05%"
)
expect(page.get_by_test_id(INFRASTRUCTURE_FEES)).to_have_text("Infrastructure0.05%")
expect(page.get_by_test_id(MAKER_FEES)).to_have_text("Maker10%")
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fees_page_discount_program_total_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("10%")
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount0%")
expect(page.get_by_test_id(REFERRAL_DISCOUNT_ROW)).to_have_text(
"Referral discount10%"
)
page.get_by_test_id(TOTAL_DISCOUNT).hover()
expect(page.get_by_test_id(TOOLTIP_CONTENT).nth(0)).to_have_text(
"The total discount is calculated according to the following formula: 1 - (1 - dvolume) ⋇ (1 - dreferral)"
)
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fees_page_referral_discount_program_referral_benefits(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(RUNNING_NOTIONAL_TAKER_VOLUME)).to_have_text("103")
expect(page.get_by_test_id(EPOCHS_IN_REFERRAL_SET)).to_have_text("1")
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fees_page_discount_program_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id(DISCOUNT_VALUE_0)).to_have_text("10%")
expect(page.get_by_test_id(DISCOUNT_VALUE_1)).to_have_text("20%")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_0)).to_have_text("100")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_1)).to_have_text("200")
expect(page.get_by_test_id(REQUIRED_EPOCHS_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(REQUIRED_EPOCHS_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id("your-referral-tier-0").nth(1)).to_be_visible()
expect(page.get_by_test_id("your-referral-tier-0").nth(1)).to_have_text("Your tier")
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fees_page_discount_program_fees_by_market(page: Page):
page.goto("/#/fees")
pinned = page.locator(PINNED_ROW_LOCATOR)
row = page.locator(ROW_LOCATOR)
expect(pinned.locator(COL_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_FEE_AFTER_DISCOUNT)).to_have_text("9.045%")
expect(row.locator(COL_INFRA_FEE)).to_have_text("0.05%")
expect(row.locator(COL_MAKER_FEE)).to_have_text("10%")
expect(row.locator(COL_LIQUIDITY_FEE)).to_have_text("0%")
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_deal_ticket_discount_program(
page: Page, setup_market_with_referral_discount_program
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-10%")
page.get_by_test_id(FEES_TEXT).hover()
tooltip = page.get_by_test_id(TOOLTIP_CONTENT).first
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_FACTOR)).to_have_text("0.05%")
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_VALUE)).to_have_text("0.0005 tDAI")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_FACTOR)).to_have_text("0%")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_VALUE)).to_have_text("0.00 tDAI")
expect(tooltip.get_by_test_id(MAKER_FEE_FACTOR)).to_have_text("10%")
expect(tooltip.get_by_test_id(MAKER_FEE_VALUE)).to_have_text("0.10 tDAI")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_FACTOR)).to_have_text("10.05%")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_VALUE)).to_have_text("0.1005 tDAI")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_FACTOR)).to_have_text("-10%")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_VALUE)).to_have_text("-0.01005 tDAI")
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.09045 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fills_taker_discount_program(
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_SIZE)).to_have_text("+1")
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text("103.50 tDAI")
expect(row.locator(COL_AGGRESSOR)).to_have_text("Taker")
expect(row.locator(COL_FEE)).to_have_text("8.42543 tDAI")
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.04017 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fills_maker_discount_program(
vega: VegaServiceNull,
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
change_keys(page, vega, 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_SIZE)).to_have_text("-1")
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text("103.50 tDAI")
expect(row.locator(COL_AGGRESSOR)).to_have_text("Maker")
expect(row.locator(COL_FEE)).to_have_text("-8.3835 tDAI")
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.035 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fills_maker_fee_tooltip_discount_program(
vega: VegaServiceNull, page: Page, setup_market_with_referral_discount_program
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
"If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-8.3835 tDAITotal fees-8.3835 tDAI"
)
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fills_taker_fee_tooltip_discount_program(
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
"If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-8.3835 tDAITotal fees-8.3835 tDAI"
)
@@ -0,0 +1,222 @@
import pytest
from fees_test_ids import *
from playwright.sync_api import Page, expect
from vega_sim.null_service import VegaServiceNull
from actions.vega import submit_order
from wallet_config import MM_WALLET
from conftest import (
init_vega,
init_page,
auth_setup,
risk_accepted_setup,
cleanup_container,
)
from actions.utils import next_epoch, change_keys, forward_time
from fixtures.market import setup_continuous_market
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(
lambda: cleanup_container(vega_instance)
)
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_referral_discount_program(vega: VegaServiceNull):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
for _ in range(2):
submit_order(vega, "Key 1", market, "SIDE_BUY", 2, 110)
forward_time(vega, True if _ < 2 - 1 else False)
return market
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fees_page_discount_program_my_trading_fees(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("8.04%-8.04%")
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
"Total fee before discount10.05%-10.05%"
)
expect(page.get_by_test_id(INFRASTRUCTURE_FEES)).to_have_text("Infrastructure0.05%")
expect(page.get_by_test_id(MAKER_FEES)).to_have_text("Maker10%")
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fees_page_discount_program_total_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("20%")
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount0%")
expect(page.get_by_test_id(REFERRAL_DISCOUNT_ROW)).to_have_text(
"Referral discount20%"
)
page.get_by_test_id(TOTAL_DISCOUNT).hover()
expect(page.get_by_test_id(TOOLTIP_CONTENT).nth(0)).to_have_text(
"The total discount is calculated according to the following formula: 1 - (1 - dvolume) ⋇ (1 - dreferral)"
)
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fees_page_referral_discount_program_referral_benefits(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(RUNNING_NOTIONAL_TAKER_VOLUME)).to_have_text("207")
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).not_to_be_visible()
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fees_page_discount_program_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id(DISCOUNT_VALUE_0)).to_have_text("10%")
expect(page.get_by_test_id(DISCOUNT_VALUE_1)).to_have_text("20%")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_0)).to_have_text("100")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_1)).to_have_text("200")
expect(page.get_by_test_id(REQUIRED_EPOCHS_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(REQUIRED_EPOCHS_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id("your-referral-tier-1").nth(1)).to_be_visible()
expect(page.get_by_test_id("your-referral-tier-1").nth(1)).to_have_text("Your tier")
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fees_page_discount_program_fees_by_market(page: Page):
page.goto("/#/fees")
pinned = page.locator(PINNED_ROW_LOCATOR)
row = page.locator(ROW_LOCATOR)
expect(pinned.locator(COL_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_FEE_AFTER_DISCOUNT)).to_have_text("8.04%")
expect(row.locator(COL_INFRA_FEE)).to_have_text("0.05%")
expect(row.locator(COL_MAKER_FEE)).to_have_text("10%")
expect(row.locator(COL_LIQUIDITY_FEE)).to_have_text("0%")
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_deal_ticket_discount_program(
page: Page, setup_market_with_referral_discount_program
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-20%")
page.get_by_test_id(FEES_TEXT).hover()
tooltip = page.get_by_test_id(TOOLTIP_CONTENT).first
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_FACTOR)).to_have_text("0.05%")
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_VALUE)).to_have_text("0.0005 tDAI")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_FACTOR)).to_have_text("0%")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_VALUE)).to_have_text("0.00 tDAI")
expect(tooltip.get_by_test_id(MAKER_FEE_FACTOR)).to_have_text("10%")
expect(tooltip.get_by_test_id(MAKER_FEE_VALUE)).to_have_text("0.10 tDAI")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_FACTOR)).to_have_text("10.05%")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_VALUE)).to_have_text("0.1005 tDAI")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_FACTOR)).to_have_text("-20%")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_VALUE)).to_have_text("-0.0201 tDAI")
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.0804 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fills_taker_discount_program(
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_SIZE)).to_have_text("+2")
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text("207.00 tDAI")
expect(row.locator(COL_AGGRESSOR)).to_have_text("Taker")
expect(row.locator(COL_FEE)).to_have_text("13.31424 tDAI")
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("4.1607 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fills_maker_discount_program(
vega: VegaServiceNull,
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
change_keys(page, vega, 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_SIZE)).to_have_text("-2")
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text("207.00 tDAI")
expect(row.locator(COL_AGGRESSOR)).to_have_text("Maker")
expect(row.locator(COL_FEE)).to_have_text("-13.248 tDAI")
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("4.14 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fills_maker_fee_tooltip_discount_program(
vega: VegaServiceNull, page: Page, setup_market_with_referral_discount_program
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
" If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-13.248 tDAITotal fees-13.248 tDAI "
)
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fills_taker_fee_tooltip_discount_program(
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
"If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-13.248 tDAITotal fees-13.248 tDAI "
)
@@ -0,0 +1,210 @@
import pytest
from fees_test_ids import *
from playwright.sync_api import Page, expect
from vega_sim.null_service import VegaServiceNull
from actions.vega import submit_order
from wallet_config import MM_WALLET
from conftest import (
init_vega,
init_page,
auth_setup,
risk_accepted_setup,
cleanup_container,
)
from actions.utils import next_epoch, change_keys, forward_time
from fixtures.market import setup_continuous_market
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(
lambda: cleanup_container(vega_instance)
)
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_volume_discount_program(vega: VegaServiceNull):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
for _ in range(2):
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega, True if _ < 2 - 1 else False)
return market
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fees_page_discount_program_my_trading_fees(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("9.045%-9.045%")
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
"Total fee before discount10.05%-10.05%"
)
expect(page.get_by_test_id(INFRASTRUCTURE_FEES)).to_have_text("Infrastructure0.05%")
expect(page.get_by_test_id(MAKER_FEES)).to_have_text("Maker10%")
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fees_page_discount_program_total_discount(
page: Page,
):
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("10%")
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount10%")
expect(page.get_by_test_id(REFERRAL_DISCOUNT_ROW)).to_have_text(
"Referral discount0%"
)
page.get_by_test_id(TOTAL_DISCOUNT).hover()
expect(page.get_by_test_id(TOOLTIP_CONTENT).nth(0)).to_have_text(
"The total discount is calculated according to the following formula: 1 - (1 - dvolume) ⋇ (1 - dreferral)"
)
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fees_page_volume_discount_program_my_current_volume(
page: Page,
):
page.goto("/#/fees")
expect(page.get_by_test_id(PAST_EPOCHS_VOLUME)).to_have_text("103")
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).to_have_text("97")
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fees_page_discount_program_discount(
page: Page,
):
page.goto("/#/fees")
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id(DISCOUNT_VALUE_0)).to_have_text("10%")
expect(page.get_by_test_id(DISCOUNT_VALUE_1)).to_have_text("20%")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_0)).to_have_text("100")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_1)).to_have_text("200")
expect(page.get_by_test_id("my-volume-value-0")).to_have_text("103")
expect(page.get_by_test_id("your-volume-tier-0").nth(1)).to_be_visible()
expect(page.get_by_test_id("your-volume-tier-0").nth(1)).to_have_text("Your tier")
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fees_page_discount_program_fees_by_market(page: Page):
page.goto("/#/fees")
pinned = page.locator(PINNED_ROW_LOCATOR)
row = page.locator(ROW_LOCATOR)
expect(pinned.locator(COL_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_FEE_AFTER_DISCOUNT)).to_have_text("9.045%")
expect(row.locator(COL_INFRA_FEE)).to_have_text("0.05%")
expect(row.locator(COL_MAKER_FEE)).to_have_text("10%")
expect(row.locator(COL_LIQUIDITY_FEE)).to_have_text("0%")
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_deal_ticket_discount_program_testing(
page: Page, setup_market_with_volume_discount_program
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-10%")
page.get_by_test_id(FEES_TEXT).hover()
tooltip = page.get_by_test_id(TOOLTIP_CONTENT).first
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_FACTOR)).to_have_text("0.05%")
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_VALUE)).to_have_text("0.0005 tDAI")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_FACTOR)).to_have_text("0%")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_VALUE)).to_have_text("0.00 tDAI")
expect(tooltip.get_by_test_id(MAKER_FEE_FACTOR)).to_have_text("10%")
expect(tooltip.get_by_test_id(MAKER_FEE_VALUE)).to_have_text("0.10 tDAI")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_FACTOR)).to_have_text("10.05%")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_VALUE)).to_have_text("0.1005 tDAI")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_FACTOR)).to_have_text("-10%")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_VALUE)).to_have_text("-0.01005 tDAI")
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.09045 tDAI")
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fills_taker_discount_program(
page: Page, setup_market_with_volume_discount_program
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_SIZE)).to_have_text("+1")
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text("103.50 tDAI")
expect(row.locator(COL_AGGRESSOR)).to_have_text("Taker")
expect(row.locator(COL_FEE)).to_have_text("9.36158 tDAI")
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.04017 tDAI")
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fills_maker_discount_program(
page: Page, setup_market_with_volume_discount_program, vega: VegaServiceNull
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
change_keys(page, vega, 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_SIZE)).to_have_text("-1")
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text("103.50 tDAI")
expect(row.locator(COL_AGGRESSOR)).to_have_text("Maker")
expect(row.locator(COL_FEE)).to_have_text("-9.315 tDAI")
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.035 tDAI")
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fills_maker_fee_tooltip_discount_program(
vega: VegaServiceNull, page: Page, setup_market_with_volume_discount_program
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
"If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-9.315 tDAITotal fees-9.315 tDAI"
)
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fills_taker_fee_tooltip_discount_program(
page: Page,
setup_market_with_volume_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
"If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-9.315 tDAITotal fees-9.315 tDAI"
)
@@ -0,0 +1,209 @@
import pytest
from fees_test_ids import *
from playwright.sync_api import Page, expect
from vega_sim.null_service import VegaServiceNull
from actions.vega import submit_order
from wallet_config import MM_WALLET
from conftest import (
init_vega,
init_page,
auth_setup,
risk_accepted_setup,
cleanup_container,
)
from actions.utils import next_epoch, change_keys, forward_time
from fixtures.market import setup_continuous_market
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(
lambda: cleanup_container(vega_instance)
)
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_volume_discount_program(vega: VegaServiceNull):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
for _ in range(3):
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega, True if _ < 3 - 1 else False)
return market
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fees_page_discount_program_my_trading_fees(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("8.04%-8.04%")
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
"Total fee before discount10.05%-10.05%"
)
expect(page.get_by_test_id(INFRASTRUCTURE_FEES)).to_have_text("Infrastructure0.05%")
expect(page.get_by_test_id(MAKER_FEES)).to_have_text("Maker10%")
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fees_page_discount_program_total_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("20%")
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount20%")
expect(page.get_by_test_id(REFERRAL_DISCOUNT_ROW)).to_have_text(
"Referral discount0%"
)
page.get_by_test_id(TOTAL_DISCOUNT).hover()
expect(page.get_by_test_id(TOOLTIP_CONTENT).nth(0)).to_have_text(
"The total discount is calculated according to the following formula: 1 - (1 - dvolume) ⋇ (1 - dreferral)"
)
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fees_page_volume_discount_program_my_current_volume(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(PAST_EPOCHS_VOLUME)).to_have_text("206")
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).not_to_be_visible()
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fees_page_discount_program_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id(DISCOUNT_VALUE_0)).to_have_text("10%")
expect(page.get_by_test_id(DISCOUNT_VALUE_1)).to_have_text("20%")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_0)).to_have_text("100")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_1)).to_have_text("200")
expect(page.get_by_test_id("my-volume-value-1")).to_have_text("206")
expect(page.get_by_test_id("your-volume-tier-1").nth(1)).to_be_visible()
expect(page.get_by_test_id("your-volume-tier-1").nth(1)).to_have_text("Your tier")
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fees_page_discount_program_fees_by_market(page: Page):
page.goto("/#/fees")
pinned = page.locator(PINNED_ROW_LOCATOR)
row = page.locator(ROW_LOCATOR)
expect(pinned.locator(COL_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_FEE_AFTER_DISCOUNT)).to_have_text("8.04%")
expect(row.locator(COL_INFRA_FEE)).to_have_text("0.05%")
expect(row.locator(COL_MAKER_FEE)).to_have_text("10%")
expect(row.locator(COL_LIQUIDITY_FEE)).to_have_text("0%")
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_deal_ticket_discount_program(
page: Page,
setup_market_with_volume_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-20%")
page.get_by_test_id(FEES_TEXT).hover()
tooltip = page.get_by_test_id(TOOLTIP_CONTENT).first
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_FACTOR)).to_have_text("0.05%")
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_VALUE)).to_have_text("0.0005 tDAI")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_FACTOR)).to_have_text("0%")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_VALUE)).to_have_text("0.00 tDAI")
expect(tooltip.get_by_test_id(MAKER_FEE_FACTOR)).to_have_text("10%")
expect(tooltip.get_by_test_id(MAKER_FEE_VALUE)).to_have_text("0.10 tDAI")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_FACTOR)).to_have_text("10.05%")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_VALUE)).to_have_text("0.1005 tDAI")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_FACTOR)).to_have_text("-20%")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_VALUE)).to_have_text("-0.0201 tDAI")
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.0804 tDAI")
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fills_taker_discount_program(
page: Page,
setup_market_with_volume_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_SIZE)).to_have_text("+1")
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text("103.50 tDAI")
expect(row.locator(COL_AGGRESSOR)).to_have_text("Taker")
expect(row.locator(COL_FEE)).to_have_text(
"8.3214 tDAI",
)
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("2.08035 tDAI")
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fills_maker_discount_program(
vega: VegaServiceNull,
page: Page,
setup_market_with_volume_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
change_keys(page, vega, 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_SIZE)).to_have_text("-1")
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text("103.50 tDAI")
expect(row.locator(COL_AGGRESSOR)).to_have_text("Maker")
expect(row.locator(COL_FEE)).to_have_text("-8.28 tDAI ")
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("2.07 tDAI")
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fills_maker_fee_tooltip_discount_program(
vega, page: Page, setup_market_with_volume_discount_program
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
"If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-8.28 tDAITotal fees-8.28 tDAI"
)
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fills_taker_fee_tooltip_discount_program(
page: Page,
setup_market_with_volume_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
page.wait_for_timeout(1000)
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
"If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-8.28 tDAITotal fees-8.28 tDAI "
)
@@ -14,7 +14,7 @@ logger = logging.getLogger()
@pytest.fixture(scope="class")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@@ -142,8 +142,7 @@ class TestGetStarted:
def test_get_started_seen_already(self, simple_market, page: Page):
page.goto(f"/#/markets/{simple_market}")
get_started_locator = page.get_by_test_id("connect-vega-wallet")
page.wait_for_selector(
'[data-testid="connect-vega-wallet"]', state="attached")
page.wait_for_selector('[data-testid="connect-vega-wallet"]', state="attached")
expect(get_started_locator).to_be_enabled
expect(get_started_locator).to_be_visible
# 0007-FUGS-015
@@ -153,7 +152,9 @@ class TestGetStarted:
expect(page.get_by_test_id("dialog-content").nth(1)).to_be_visible()
@pytest.mark.skip("tbd-market-sim")
def test_redirect_default_market(self, continuous_market, vega: VegaServiceNull, page: Page):
def test_redirect_default_market(
self, continuous_market, vega: VegaServiceNull, page: Page
):
page.goto("/")
# 0007-FUGS-012
expect(page).to_have_url(
@@ -8,7 +8,7 @@ from actions.utils import next_epoch, truncate_middle, change_keys
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@@ -11,7 +11,7 @@ from actions.utils import next_epoch
@pytest.fixture(scope="class")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@@ -11,7 +11,7 @@ market_title_test_id = "accordion-title"
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@@ -14,7 +14,7 @@ col_market_id = '[col-id="market"] [data-testid="stack-cell-primary"]'
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@@ -16,7 +16,7 @@ COL_ID_FEE = ".ag-center-cols-container [col-id='fee'] .ag-cell-value"
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@@ -7,11 +7,10 @@ from conftest import init_page, init_vega, cleanup_container
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
# we can reuse single page instance in all tests
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
@@ -49,7 +49,7 @@ def markets(vega: VegaServiceNull):
price=130,
)
vega.forward("10s")
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -63,7 +63,7 @@ def markets(vega: VegaServiceNull):
price=88,
)
vega.forward("10s")
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -77,7 +77,7 @@ def markets(vega: VegaServiceNull):
price=88,
)
vega.forward("10s")
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -92,7 +92,7 @@ def markets(vega: VegaServiceNull):
wait=False,
)
vega.forward("10s")
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -105,7 +105,7 @@ def markets(vega: VegaServiceNull):
volume=100,
price=104,
)
vega.forward("10s")
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -120,7 +120,7 @@ def markets(vega: VegaServiceNull):
expires_at=vega.get_blockchain_time() + 5 * 1e9,
)
vega.forward("10s")
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -134,7 +134,7 @@ def markets(vega: VegaServiceNull):
volume=20,
)
vega.forward("10s")
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -148,7 +148,7 @@ def markets(vega: VegaServiceNull):
volume=40,
)
vega.forward("10s")
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -162,7 +162,7 @@ def markets(vega: VegaServiceNull):
volume=60,
)
vega.forward("10s")
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -177,7 +177,7 @@ def markets(vega: VegaServiceNull):
volume=60,
)
vega.forward("10s")
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -190,8 +190,7 @@ def markets(vega: VegaServiceNull):
volume=10,
price=150,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -205,7 +204,6 @@ def markets(vega: VegaServiceNull):
price=160,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -219,7 +217,6 @@ def markets(vega: VegaServiceNull):
price=60,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -395,7 +392,6 @@ def test_order_amend_order(vega: VegaServiceNull, page: Page):
page.get_by_role("button", name="Update").click()
wait_for_toast_confirmation(page, timeout=5000)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(page.locator('[row-index="1"]').first).to_contain_text(
@@ -414,7 +410,6 @@ def test_order_cancel_single_order(vega: VegaServiceNull, page: Page):
page.get_by_test_id("cancel").first.click()
wait_for_toast_confirmation(page, timeout=5000)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(page.locator('[row-index="0"]').first).to_contain_text(
@@ -434,7 +429,6 @@ def test_order_cancel_all_orders(vega: VegaServiceNull, page: Page):
page.get_by_test_id("cancelAll").click()
wait_for_toast_confirmation(page, timeout=5000)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -10,7 +10,7 @@ from wallet_config import MM_WALLET, MM_WALLET2
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@@ -18,7 +18,7 @@ class TestPerpetuals:
@pytest.fixture(scope="class")
def vega(self, request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@pytest.fixture(scope="class")
@@ -12,7 +12,7 @@ COL_ID_USED = ".ag-center-cols-container [col-id='used'] .ag-cell-value"
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@@ -15,7 +15,7 @@ BUY_ORDERS = [[1, 106], [1, 107], [1, 108]]
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@@ -119,7 +119,7 @@ def setup_market_and_referral_scheme(vega: VegaServiceNull, continuous_market: s
forward_time(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_can_traverse_up_and_down_through_tiers(continuous_market, vega: VegaServiceNull, page: Page):
setup_market_and_referral_scheme(vega, continuous_market, page)
change_keys(page, vega, PARTY_B.name)
@@ -163,7 +163,7 @@ def test_can_traverse_up_and_down_through_tiers(continuous_market, vega: VegaSer
"1%", "1", "1%", "0", "1", "1"))
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_does_not_move_up_tiers_when_not_enough_epochs(continuous_market, vega: VegaServiceNull, page: Page):
setup_market_and_referral_scheme(vega, continuous_market, page)
change_keys(page, vega, PARTY_B.name)
@@ -0,0 +1,62 @@
from actions.utils import create_and_faucet_wallet
from wallet_config import WalletConfig
# region Constants
ACTIVITY = "activity"
HOARDER = "hoarder"
COMBO = "combo"
REWARDS_URL = "/#/rewards"
# test IDs
COMBINED_MULTIPLIERS = "combined-multipliers"
TOTAL_REWARDS = "total-rewards"
PRICE_TAKING_COL_ID = '[col-id="priceTaking"]'
TOTAL_COL_ID = '[col-id="total"]'
ROW = "row"
STREAK_REWARD_MULTIPLIER_VALUE = "streak-reward-multiplier-value"
HOARDER_REWARD_MULTIPLIER_VALUE = "hoarder-reward-multiplier-value"
HOARDER_BONUS_TOTAL_HOARDED = "hoarder-bonus-total-hoarded"
EARNED_BY_ME_BUTTON = "earned-by-me-button"
TRANSFER_AMOUNT = "transfer-amount"
EPOCH_STREAK = "epoch-streak"
# endregion
# Keys
PARTY_A = "PARTY_A"
PARTY_B = "PARTY_B"
PARTY_C = "PARTY_C"
PARTY_D = "PARTY_D"
ACTIVITY_STREAKS = """
{
"tiers": [
{
"minimum_activity_streak": 2,
"reward_multiplier": "2.0",
"vesting_multiplier": "1.1"
}
]
}
"""
VESTING = """
{
"tiers": [
{
"minimum_quantum_balance": "10000000",
"reward_multiplier": "2"
}
]
}
"""
def keys(vega):
PARTY_A = WalletConfig("PARTY_A", "PARTY_A")
create_and_faucet_wallet(vega=vega, wallet=PARTY_A)
PARTY_B = WalletConfig("PARTY_B", "PARTY_B")
create_and_faucet_wallet(vega=vega, wallet=PARTY_B)
PARTY_C = WalletConfig("PARTY_C", "PARTY_C")
create_and_faucet_wallet(vega=vega, wallet=PARTY_C)
PARTY_D = WalletConfig("PARTY_D", "PARTY_D")
create_and_faucet_wallet(vega=vega, wallet=PARTY_D)
return PARTY_A, PARTY_B, PARTY_C, PARTY_D
@@ -0,0 +1,121 @@
import pytest
import vega_sim.proto.vega as vega_protos
from rewards_test_ids import *
from playwright.sync_api import Page, expect
from conftest import init_vega, init_page, auth_setup, risk_accepted_setup, cleanup_container
from fixtures.market import setup_continuous_market
from actions.utils import next_epoch, change_keys
from wallet_config import MM_WALLET
from vega_sim.null_service import VegaServiceNull
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
page.goto(REWARDS_URL)
change_keys(page, vega, PARTY_B)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_reward_program(vega: VegaServiceNull):
tDAI_market = setup_continuous_market(vega)
PARTY_A, PARTY_B, PARTY_C, PARTY_D = keys(vega)
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
vega.mint(key_name=PARTY_B.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_C.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_A.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_D.name, asset=tDAI_asset_id, amount=100000)
next_epoch(vega=vega)
vega.update_network_parameter(
proposal_key=MM_WALLET.name,
parameter="rewards.vesting.benefitTiers",
new_value=VESTING,
)
next_epoch(vega=vega)
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
vega.update_network_parameter(
MM_WALLET.name, parameter="reward.asset", new_value=tDAI_asset_id
)
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",
asset_for_metric=tDAI_asset_id,
metric=vega_protos.vega.DISPATCH_METRIC_MAKER_FEES_PAID,
amount=100,
factor=1.0,
)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_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=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
return tDAI_market, tDAI_asset_id
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_0")
def test_network_reward_pot(
page: Page,
):
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text("50.00 tDAI")
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_0")
def test_reward_multiplier(
page: Page,
):
expect(page.get_by_test_id(COMBINED_MULTIPLIERS)).to_have_text("1x")
expect(page.get_by_test_id(STREAK_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
expect(page.get_by_test_id(HOARDER_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_0")
def test_hoarder_bonus(
page: Page,
):
expect(page.get_by_test_id(HOARDER_BONUS_TOTAL_HOARDED)).to_contain_text(
"5,000,000"
)
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_0")
def test_reward_history(
page: Page,
):
page.locator('[name="fromEpoch"]').fill("1")
expect((page.get_by_role(ROW).locator(PRICE_TAKING_COL_ID)).nth(1)).to_have_text(
"100.00100.00%"
)
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text("100.00")
page.get_by_test_id(EARNED_BY_ME_BUTTON).click()
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text("50.00")
@@ -0,0 +1,173 @@
import pytest
from rewards_test_ids import *
import vega_sim.proto.vega as vega_protos
from playwright.sync_api import Page, expect
from conftest import init_vega, init_page, auth_setup, risk_accepted_setup, cleanup_container
from fixtures.market import setup_continuous_market
from actions.utils import next_epoch, change_keys
from wallet_config import MM_WALLET
from vega_sim.null_service import VegaServiceNull
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
page.goto(REWARDS_URL)
change_keys(page, vega, PARTY_B)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_reward_program(vega: VegaServiceNull):
tDAI_market = setup_continuous_market(vega)
PARTY_A, PARTY_B, PARTY_C, PARTY_D = keys(vega)
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
vega.mint(key_name=PARTY_B.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_C.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_A.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_D.name, asset=tDAI_asset_id, amount=100000)
next_epoch(vega=vega)
vega.update_network_parameter(
proposal_key=MM_WALLET.name,
parameter="rewards.vesting.benefitTiers",
new_value=VESTING,
)
next_epoch(vega=vega)
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
vega.update_network_parameter(
MM_WALLET.name, parameter="reward.asset", new_value=tDAI_asset_id
)
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",
asset_for_metric=tDAI_asset_id,
metric=vega_protos.vega.DISPATCH_METRIC_MAKER_FEES_PAID,
amount=100,
factor=1.0,
)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_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=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_market,
order_type="TYPE_LIMIT",
time_in_force="TIME_IN_FORCE_GTC",
side="SIDE_BUY",
price=1,
volume=1,
)
next_epoch(vega=vega)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.submit_order(
trading_key=PARTY_D.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
next_epoch(vega=vega)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.submit_order(
trading_key=PARTY_D.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
next_epoch(vega=vega)
next_epoch(vega=vega)
return tDAI_market, tDAI_asset_id
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_1")
def test_network_reward_pot(
page: Page,
):
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text("166.66666 tDAI")
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_1")
def test_reward_multiplier(
page: Page,
):
expect(page.get_by_test_id(COMBINED_MULTIPLIERS)).to_have_text("2x")
expect(page.get_by_test_id(STREAK_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
expect(page.get_by_test_id(HOARDER_REWARD_MULTIPLIER_VALUE)).to_have_text("2x")
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_1")
def test_hoarder_bonus(page: Page):
expect(page.get_by_test_id(HOARDER_BONUS_TOTAL_HOARDED)).to_contain_text(
"16,666,666"
)
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_1")
def test_reward_history(page: Page):
page.locator('[name="fromEpoch"]').fill("1")
expect((page.get_by_role(ROW).locator(PRICE_TAKING_COL_ID)).nth(1)).to_have_text(
"299.99999100.00%"
)
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text(
"299.99999"
)
page.get_by_test_id(EARNED_BY_ME_BUTTON).click()
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text(
"166.66666"
)
@@ -1,475 +0,0 @@
import pytest
import vega_sim.proto.vega as vega_protos
from playwright.sync_api import Page, expect
from conftest import init_vega, init_page, auth_setup, cleanup_container
from fixtures.market import setup_continuous_market, market_exists
from actions.utils import next_epoch, change_keys
from wallet_config import MM_WALLET, PARTY_A, PARTY_B, PARTY_C, PARTY_D
from vega_sim.null_service import VegaServiceNull
# region Constants
ACTIVITY = "activity"
HOARDER = "hoarder"
COMBO = "combo"
REWARDS_URL = "/#/rewards"
# test IDs
COMBINED_MULTIPLIERS = "combined-multipliers"
TOTAL_REWARDS = "total-rewards"
PRICE_TAKING_COL_ID = '[col-id="priceTaking"]'
TOTAL_COL_ID = '[col-id="total"]'
ROW = "row"
STREAK_REWARD_MULTIPLIER_VALUE = "streak-reward-multiplier-value"
HOARDER_REWARD_MULTIPLIER_VALUE = "hoarder-reward-multiplier-value"
HOARDER_BONUS_TOTAL_HOARDED = "hoarder-bonus-total-hoarded"
EARNED_BY_ME_BUTTON = "earned-by-me-button"
TRANSFER_AMOUNT = "transfer-amount"
EPOCH_STREAK = "epoch-streak"
# endregion
@pytest.fixture(scope="module")
def market_ids():
return {
"vega_activity_tier_0": "default_id",
"vega_hoarder_tier_0": "default_id",
"vega_combo_tier_0": "default_id",
"vega_activity_tier_1": "default_id",
"vega_hoarder_tier_1": "default_id",
"vega_combo_tier_1": "default_id",
}
@pytest.fixture(scope="module")
def vega_activity_tier_0(request):
with init_vega(request) as vega_activity_tier_0:
request.addfinalizer(lambda: cleanup_container(vega_activity_tier_0)) # Register the cleanup function
yield vega_activity_tier_0
@pytest.fixture(scope="module")
def vega_hoarder_tier_0(request):
with init_vega(request) as vega_hoarder_tier_0:
request.addfinalizer(lambda: cleanup_container(vega_hoarder_tier_0)) # Register the cleanup function
yield vega_hoarder_tier_0
@pytest.fixture(scope="module")
def vega_combo_tier_0(request):
with init_vega(request) as vega_combo_tier_0:
request.addfinalizer(lambda: cleanup_container(vega_combo_tier_0)) # Register the cleanup function
yield vega_combo_tier_0
@pytest.fixture(scope="module")
def vega_activity_tier_1(request):
with init_vega(request) as vega_activity_tier_1:
request.addfinalizer(lambda: cleanup_container(vega_activity_tier_1)) # Register the cleanup function
yield vega_activity_tier_1
@pytest.fixture(scope="module")
def vega_hoarder_tier_1(request):
with init_vega(request) as vega_hoarder_tier_1:
request.addfinalizer(lambda: cleanup_container(vega_hoarder_tier_1)) # Register the cleanup function
yield vega_hoarder_tier_1
@pytest.fixture(scope="module")
def vega_combo_tier_1(request):
with init_vega(request) as vega_combo_tier_1:
request.addfinalizer(lambda: cleanup_container(vega_combo_tier_1)) # Register the cleanup function
yield vega_combo_tier_1
@pytest.fixture
def auth(vega_instance, page):
return auth_setup(vega_instance, page)
@pytest.fixture
def page(vega_instance, browser, request):
with init_page(vega_instance, browser, request) as page_instance:
yield page_instance
@pytest.fixture
def vega_instance(
reward_program,
vega_activity_tier_0,
vega_hoarder_tier_0,
vega_combo_tier_0,
vega_activity_tier_1,
vega_hoarder_tier_1,
vega_combo_tier_1,
tier,
):
if reward_program == "activity":
return vega_activity_tier_0 if tier == 1 else vega_activity_tier_1
elif reward_program == "hoarder":
return vega_hoarder_tier_0 if tier == 1 else vega_hoarder_tier_1
elif reward_program == "combo":
return vega_combo_tier_0 if tier == 1 else vega_combo_tier_1
def setup_market_with_reward_program(vega: VegaServiceNull, reward_programs, tier):
print(f"Started setup_market_with_{reward_programs}_{tier}")
tDAI_market = setup_continuous_market(vega)
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
vega.mint(key_name=PARTY_B.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_C.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_A.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_D.name, asset=tDAI_asset_id, amount=100000)
next_epoch(vega=vega)
if ACTIVITY in reward_programs:
vega.update_network_parameter(
proposal_key=MM_WALLET.name,
parameter="rewards.activityStreak.benefitTiers",
new_value=ACTIVITY_STREAKS,
)
print("update_network_parameter activity done")
next_epoch(vega=vega)
if HOARDER in reward_programs:
vega.update_network_parameter(
proposal_key=MM_WALLET.name,
parameter="rewards.vesting.benefitTiers",
new_value=VESTING,
)
next_epoch(vega=vega)
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
vega.update_network_parameter(
MM_WALLET.name, parameter="reward.asset", new_value=tDAI_asset_id
)
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",
asset_for_metric=tDAI_asset_id,
metric=vega_protos.vega.DISPATCH_METRIC_MAKER_FEES_PAID,
# lock_period= 5,
# TODO test lock period
amount=100,
factor=1.0,
)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_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=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_for_total_catchup()
if tier == 1:
next_epoch(vega=vega)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_market,
order_type="TYPE_LIMIT",
time_in_force="TIME_IN_FORCE_GTC",
side="SIDE_BUY",
price=1,
volume=1,
)
next_epoch(vega=vega)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.submit_order(
trading_key=PARTY_D.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
next_epoch(vega=vega)
if HOARDER in reward_programs:
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.submit_order(
trading_key=PARTY_D.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
next_epoch(vega=vega)
next_epoch(vega=vega)
return tDAI_market, tDAI_asset_id
def set_market_reward_program(vega, reward_program, market_ids, tier):
market_id_key = f"vega_{reward_program}_tier_{tier}"
if reward_program == COMBO:
market_id_key = COMBO
market_id = market_ids.get(market_id_key, "default_id")
print(f"Checking if market exists: {market_id}")
if not market_exists(vega, market_id):
print(
f"Market doesn't exist for {reward_program} {tier}. Setting up new market."
)
reward_programs = [reward_program]
if reward_program == COMBO:
reward_programs = [ACTIVITY, HOARDER]
market_id, _ = setup_market_with_reward_program(vega, reward_programs, tier)
market_ids[market_id_key] = market_id
return market_id, market_ids
ACTIVITY_STREAKS = """
{
"tiers": [
{
"minimum_activity_streak": 2,
"reward_multiplier": "2.0",
"vesting_multiplier": "1.1"
}
]
}
"""
VESTING = """
{
"tiers": [
{
"minimum_quantum_balance": "10000000",
"reward_multiplier": "2"
}
]
}
"""
@pytest.mark.parametrize(
"reward_program, tier, total_rewards",
[
(ACTIVITY, 0, "50.00 tDAI"),
(HOARDER, 0, "50.00 tDAI"),
(COMBO, 0, "50.00 tDAI"),
(ACTIVITY, 1, "116.66666 tDAI"),
(HOARDER, 1, "166.66666 tDAI "),
(COMBO, 1, "183.33333 tDAI"),
],
)
@pytest.mark.usefixtures("auth", "risk_accepted", "market_ids")
def test_network_reward_pot(
reward_program,
vega_instance: VegaServiceNull,
page: Page,
total_rewards,
tier,
market_ids,
):
print("reward program: " + reward_program, " tier:", tier)
market_id, market_ids = set_market_reward_program(
vega_instance, reward_program, market_ids, tier
)
page.goto(REWARDS_URL)
change_keys(page, vega_instance, PARTY_B.name)
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text(total_rewards)
@pytest.mark.parametrize(
"reward_program, tier, reward_multiplier, streak_multiplier, hoarder_multiplier",
[
(ACTIVITY, 0, "1x", "1x", "1x"),
(HOARDER, 0, "1x", "1x", "1x"),
(COMBO, 0, "1x", "1x", "1x"),
(ACTIVITY, 1, "2x", "2x", "1x"),
(HOARDER, 1, "2x", "1x", "2x"),
(COMBO, 1, "4x", "2x", "2x"),
],
)
@pytest.mark.usefixtures("auth", "risk_accepted", "market_ids")
def test_reward_multiplier(
reward_program,
vega_instance: VegaServiceNull,
page: Page,
reward_multiplier,
streak_multiplier,
hoarder_multiplier,
tier,
market_ids,
):
print("reward program: " + reward_program, " tier:", tier)
market_id, market_ids = set_market_reward_program(
vega_instance, reward_program, market_ids, tier
)
page.goto(REWARDS_URL)
change_keys(page, vega_instance, PARTY_B.name)
expect(page.get_by_test_id(COMBINED_MULTIPLIERS)).to_have_text(reward_multiplier)
expect(page.get_by_test_id(STREAK_REWARD_MULTIPLIER_VALUE)).to_have_text(
streak_multiplier
)
expect(page.get_by_test_id(HOARDER_REWARD_MULTIPLIER_VALUE)).to_have_text(
hoarder_multiplier
)
@pytest.mark.parametrize(
"reward_program, tier, epoch_streak",
[
(ACTIVITY, 0, "1"),
(ACTIVITY, 1, "7"),
],
)
@pytest.mark.usefixtures("auth", "risk_accepted", "market_ids")
def test_activity_streak(
reward_program,
vega_instance: VegaServiceNull,
page: Page,
epoch_streak,
tier,
market_ids,
):
print("reward program: " + reward_program, " tier:", tier)
market_id, market_ids = set_market_reward_program(
vega_instance, reward_program, market_ids, tier
)
page.goto(REWARDS_URL)
change_keys(page, vega_instance, PARTY_B.name)
if tier == 1:
expect(page.get_by_test_id(EPOCH_STREAK)).to_have_text(
"Active trader: " + epoch_streak + " epochs so far (Tier 1 as of last epoch)"
)
else:
expect(page.get_by_test_id(EPOCH_STREAK)).to_have_text(
"Active trader: " + epoch_streak + " epochs so far "
)
@pytest.mark.parametrize(
"reward_program, tier, rewards_hoarded",
[
(HOARDER, 0, "5,000,000"),
(HOARDER, 1, "16,666,666"),
],
)
@pytest.mark.usefixtures("auth", "risk_accepted", "market_ids")
def test_hoarder_bonus(
reward_program,
vega_instance: VegaServiceNull,
page: Page,
rewards_hoarded,
tier,
market_ids,
):
print("reward program: " + reward_program, " tier:", tier)
market_id, market_ids = set_market_reward_program(
vega_instance, reward_program, market_ids, tier
)
page.goto(REWARDS_URL)
change_keys(page, vega_instance, PARTY_B.name)
expect(page.get_by_test_id(HOARDER_BONUS_TOTAL_HOARDED)).to_contain_text(
rewards_hoarded
)
@pytest.mark.parametrize(
"reward_program, tier, price_taking, total, earned_by_me",
[
(ACTIVITY, 0, "100.00100.00%", "100.00", "50.00"),
(HOARDER, 0, "100.00100.00%", "100.00", "50.00"),
(COMBO, 0, "100.00100.00%", "100.00", "50.00"),
(ACTIVITY, 1, "300.00100.00%", "300.00", "116.66666"),
(HOARDER, 1, "299.99999100.00%", "299.99999", "166.66666"),
(COMBO, 1, "299.99999100.00%", "299.99999", "183.33333"),
],
)
@pytest.mark.usefixtures("auth", "risk_accepted", "market_ids")
def test_reward_history(
reward_program,
vega_instance: VegaServiceNull,
page: Page,
price_taking,
total,
earned_by_me,
tier,
market_ids,
):
print("reward program: " + reward_program, " tier:", tier)
market_id, market_ids = set_market_reward_program(
vega_instance, reward_program, market_ids, tier
)
page.goto(REWARDS_URL)
change_keys(page, vega_instance, PARTY_B.name)
page.locator('[name="fromEpoch"]').fill("1")
expect((page.get_by_role(ROW).locator(PRICE_TAKING_COL_ID)).nth(1)).to_have_text(
price_taking
)
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text(total)
page.get_by_test_id(EARNED_BY_ME_BUTTON).click()
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text(
earned_by_me
)
@pytest.mark.parametrize(
"reward_program, tier",
[
(ACTIVITY, 1),
],
)
@pytest.mark.usefixtures("auth", "risk_accepted", "market_ids")
def test_redeem(
reward_program, vega_instance: VegaServiceNull, page: Page, tier, market_ids
):
print("reward program: " + reward_program, " tier:", tier)
market_id, market_ids = set_market_reward_program(
vega_instance, reward_program, market_ids, tier
)
page.goto(REWARDS_URL)
change_keys(page, vega_instance, PARTY_B.name)
page.get_by_test_id("redeem-rewards-button").click()
available_to_withdraw = page.get_by_test_id(
"available-to-withdraw-value"
).text_content()
option_value = page.locator(
'[data-testid="transfer-form"] [name="fromAccount"] option[value^="ACCOUNT_TYPE_VESTED_REWARDS"]'
).first.get_attribute("value")
page.select_option(
'[data-testid="transfer-form"] [name="fromAccount"]', option_value
)
page.get_by_test_id("use-max-button").first.click()
expect(page.get_by_test_id(TRANSFER_AMOUNT)).to_have_text(available_to_withdraw)
@@ -1,49 +1,27 @@
import pytest
from rewards_test_ids import *
import vega_sim.proto.vega as vega_protos
from playwright.sync_api import Page, expect
from conftest import init_vega, init_page, auth_setup, risk_accepted_setup, cleanup_container
from conftest import (
init_vega,
init_page,
auth_setup,
risk_accepted_setup,
cleanup_container,
)
from fixtures.market import setup_continuous_market
from actions.utils import next_epoch, change_keys, create_and_faucet_wallet
from wallet_config import MM_WALLET, WalletConfig
from actions.utils import next_epoch, change_keys
from wallet_config import MM_WALLET
from vega_sim.null_service import VegaServiceNull
# region Constants
ACTIVITY = "activity"
HOARDER = "hoarder"
COMBO = "combo"
REWARDS_URL = "/#/rewards"
# test IDs
COMBINED_MULTIPLIERS = "combined-multipliers"
TOTAL_REWARDS = "total-rewards"
PRICE_TAKING_COL_ID = '[col-id="priceTaking"]'
TOTAL_COL_ID = '[col-id="total"]'
ROW = "row"
STREAK_REWARD_MULTIPLIER_VALUE = "streak-reward-multiplier-value"
HOARDER_REWARD_MULTIPLIER_VALUE = "hoarder-reward-multiplier-value"
HOARDER_BONUS_TOTAL_HOARDED = "hoarder-bonus-total-hoarded"
EARNED_BY_ME_BUTTON = "earned-by-me-button"
TRANSFER_AMOUNT = "transfer-amount"
EPOCH_STREAK = "epoch-streak"
# endregion
# Keys
PARTY_A = "PARTY_A"
PARTY_B = "PARTY_B"
PARTY_C = "PARTY_C"
PARTY_D = "PARTY_D"
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
@@ -106,55 +84,31 @@ def setup_market_with_reward_program(vega: VegaServiceNull):
side="SIDE_BUY",
volume=1,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
return tDAI_market, tDAI_asset_id
ACTIVITY_STREAKS = """
{
"tiers": [
{
"minimum_activity_streak": 2,
"reward_multiplier": "2.0",
"vesting_multiplier": "1.1"
}
]
}
"""
def keys(vega):
PARTY_A = WalletConfig("PARTY_A", "PARTY_A")
create_and_faucet_wallet(vega=vega, wallet=PARTY_A)
PARTY_B = WalletConfig("PARTY_B", "PARTY_B")
create_and_faucet_wallet(vega=vega, wallet=PARTY_B)
PARTY_C = WalletConfig("PARTY_C", "PARTY_C")
create_and_faucet_wallet(vega=vega, wallet=PARTY_C)
PARTY_D = WalletConfig("PARTY_D", "PARTY_D")
create_and_faucet_wallet(vega=vega, wallet=PARTY_D)
return PARTY_A, PARTY_B, PARTY_C, PARTY_D
@pytest.mark.xdist_group(name="test_rewards_activity_tier_0")
def test_network_reward_pot(
page: Page,
):
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text("50.00 tDAI")
page.pause()
@pytest.mark.xdist_group(name="test_rewards_activity_tier_0")
def test_reward_multiplier(
page: Page,
):
page.pause()
expect(page.get_by_test_id(COMBINED_MULTIPLIERS)).to_have_text("1x")
expect(page.get_by_test_id(STREAK_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
expect(page.get_by_test_id(HOARDER_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
@pytest.mark.xdist_group(name="test_rewards_activity_tier_0")
""" @pytest.mark.xdist_group(name="test_rewards_activity_tier_0")
def test_activity_streak(
page: Page,
):
@@ -174,3 +128,4 @@ def test_reward_history(
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text("100.00")
page.get_by_test_id(EARNED_BY_ME_BUTTON).click()
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text("50.00")
"""
@@ -0,0 +1,187 @@
import pytest
from rewards_test_ids import *
import vega_sim.proto.vega as vega_protos
from playwright.sync_api import Page, expect
from conftest import init_vega, init_page, auth_setup, risk_accepted_setup, cleanup_container
from fixtures.market import setup_continuous_market
from actions.utils import next_epoch, change_keys
from wallet_config import MM_WALLET
from vega_sim.null_service import VegaServiceNull
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
page.goto(REWARDS_URL)
change_keys(page, vega, PARTY_B)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_reward_program(vega: VegaServiceNull):
tDAI_market = setup_continuous_market(vega)
PARTY_A, PARTY_B, PARTY_C, PARTY_D = keys(vega)
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
vega.mint(key_name=PARTY_B.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_C.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_A.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_D.name, asset=tDAI_asset_id, amount=100000)
next_epoch(vega=vega)
vega.update_network_parameter(
proposal_key=MM_WALLET.name,
parameter="rewards.activityStreak.benefitTiers",
new_value=ACTIVITY_STREAKS,
)
print("update_network_parameter activity done")
next_epoch(vega=vega)
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
vega.update_network_parameter(
MM_WALLET.name, parameter="reward.asset", new_value=tDAI_asset_id
)
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",
asset_for_metric=tDAI_asset_id,
metric=vega_protos.vega.DISPATCH_METRIC_MAKER_FEES_PAID,
# lock_period= 5,
# TODO test lock period
amount=100,
factor=1.0,
)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_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=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_market,
order_type="TYPE_LIMIT",
time_in_force="TIME_IN_FORCE_GTC",
side="SIDE_BUY",
price=1,
volume=1,
)
next_epoch(vega=vega)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.submit_order(
trading_key=PARTY_D.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
next_epoch(vega=vega)
vega.submit_order(
trading_key=PARTY_D.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
next_epoch(vega=vega)
next_epoch(vega=vega)
return tDAI_market, tDAI_asset_id
@pytest.mark.xdist_group(name="test_rewards_activity_tier_1")
def test_network_reward_pot(page: Page):
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text("116.66666 tDAI")
@pytest.mark.xdist_group(name="test_rewards_activity_tier_1")
def test_reward_multiplier(
page: Page,
):
expect(page.get_by_test_id(COMBINED_MULTIPLIERS)).to_have_text("2x")
expect(page.get_by_test_id(STREAK_REWARD_MULTIPLIER_VALUE)).to_have_text("2x")
expect(page.get_by_test_id(HOARDER_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
@pytest.mark.xdist_group(name="test_rewards_activity_tier_1")
def test_activity_streak(
page: Page,
):
expect(page.get_by_test_id(EPOCH_STREAK)).to_have_text(
"Active trader: 7 epochs so far (Tier 1 as of last epoch)"
)
@pytest.mark.xdist_group(name="test_rewards_activity_tier_1")
def test_reward_history(
page: Page,
):
page.locator('[name="fromEpoch"]').fill("1")
expect((page.get_by_role(ROW).locator(PRICE_TAKING_COL_ID)).nth(1)).to_have_text(
"300.00100.00%"
)
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text("300.00")
page.get_by_test_id(EARNED_BY_ME_BUTTON).click()
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text(
"116.66666"
)
@pytest.mark.xdist_group(name="test_rewards_activity_tier_1")
def test_redeem(
page: Page,
):
page.get_by_test_id("redeem-rewards-button").click()
available_to_withdraw = page.get_by_test_id(
"available-to-withdraw-value"
).text_content()
option_value = page.locator(
'[data-testid="transfer-form"] [name="fromAccount"] option[value^="ACCOUNT_TYPE_VESTED_REWARDS"]'
).first.get_attribute("value")
page.select_option(
'[data-testid="transfer-form"] [name="fromAccount"]', option_value
)
page.get_by_test_id("use-max-button").first.click()
expect(page.get_by_test_id(TRANSFER_AMOUNT)).to_have_text(available_to_withdraw)
@@ -0,0 +1,174 @@
import pytest
from rewards_test_ids import *
import vega_sim.proto.vega as vega_protos
from playwright.sync_api import Page, expect
from conftest import init_vega, init_page, auth_setup, risk_accepted_setup, cleanup_container
from fixtures.market import setup_continuous_market
from actions.utils import next_epoch, change_keys
from wallet_config import MM_WALLET
from vega_sim.null_service import VegaServiceNull
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
page.goto(REWARDS_URL)
change_keys(page, vega, PARTY_B)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_reward_program(vega: VegaServiceNull):
tDAI_market = setup_continuous_market(vega)
PARTY_A, PARTY_B, PARTY_C, PARTY_D = keys(vega)
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
vega.mint(key_name=PARTY_B.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_C.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_A.name, asset=tDAI_asset_id, amount=100000)
vega.mint(key_name=PARTY_D.name, asset=tDAI_asset_id, amount=100000)
next_epoch(vega=vega)
vega.update_network_parameter(
proposal_key=MM_WALLET.name,
parameter="rewards.activityStreak.benefitTiers",
new_value=ACTIVITY_STREAKS,
)
print("update_network_parameter activity done")
next_epoch(vega=vega)
vega.update_network_parameter(
proposal_key=MM_WALLET.name,
parameter="rewards.vesting.benefitTiers",
new_value=VESTING,
)
next_epoch(vega=vega)
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
vega.update_network_parameter(
MM_WALLET.name, parameter="reward.asset", new_value=tDAI_asset_id
)
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",
asset_for_metric=tDAI_asset_id,
metric=vega_protos.vega.DISPATCH_METRIC_MAKER_FEES_PAID,
amount=100,
factor=1.0,
)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_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=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_market,
order_type="TYPE_LIMIT",
time_in_force="TIME_IN_FORCE_GTC",
side="SIDE_BUY",
price=1,
volume=1,
)
next_epoch(vega=vega)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.submit_order(
trading_key=PARTY_D.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
next_epoch(vega=vega)
vega.submit_order(
trading_key=PARTY_B.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.submit_order(
trading_key=PARTY_D.name,
market_id=tDAI_market,
order_type="TYPE_MARKET",
time_in_force="TIME_IN_FORCE_IOC",
side="SIDE_BUY",
volume=1,
)
vega.wait_for_total_catchup()
next_epoch(vega=vega)
next_epoch(vega=vega)
next_epoch(vega=vega)
return tDAI_market, tDAI_asset_id
@pytest.mark.xdist_group(name="test_rewards_combo_tier_1")
def test_network_reward_pot( page: Page
):
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text("183.33333 tDAI")
@pytest.mark.xdist_group(name="test_rewards_combo_tier_1")
def test_reward_multiplier(
page: Page,
):
expect(page.get_by_test_id(COMBINED_MULTIPLIERS)).to_have_text("4x")
expect(page.get_by_test_id(STREAK_REWARD_MULTIPLIER_VALUE)).to_have_text(
"2x"
)
expect(page.get_by_test_id(HOARDER_REWARD_MULTIPLIER_VALUE)).to_have_text(
"2x"
)
@pytest.mark.xdist_group(name="test_rewards_combo_tier_1")
def test_reward_history(
page: Page,
):
page.locator('[name="fromEpoch"]').fill("1")
expect((page.get_by_role(ROW).locator(PRICE_TAKING_COL_ID)).nth(1)).to_have_text(
"299.99999100.00%"
)
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text("299.99999")
page.get_by_test_id(EARNED_BY_ME_BUTTON).click()
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text(
"183.33333"
)
@@ -43,6 +43,7 @@ def test_vesting(continuous_market, vega: VegaServiceNull, page: Page):
side="SIDE_BUY",
volume=1,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.goto("/#/rewards")
@@ -6,7 +6,7 @@ from conftest import init_vega, cleanup_container
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
+5 -6
View File
@@ -14,7 +14,7 @@ def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(
lambda: cleanup_container(vega_instance)
) # Register the cleanup function
)
yield vega_instance
@@ -242,12 +242,12 @@ def test_team_page_headline(team_page: Page, setup_teams_and_games):
expect(team_page.get_by_test_id("team-name")).to_have_text(team_name)
expect(team_page.get_by_test_id("members-count-stat")).to_have_text("4")
expect(team_page.get_by_test_id("total-games-stat")).to_have_text("2")
expect(team_page.get_by_test_id("total-games-stat")).to_have_text("1")
# TODO this still seems wrong as its always 0
expect(team_page.get_by_test_id("total-volume-stat")).to_have_text("0")
expect(team_page.get_by_test_id("rewards-paid-stat")).to_have_text("1.2k")
expect(team_page.get_by_test_id("rewards-paid-stat")).to_have_text("500")
def test_switch_teams(team_page: Page, vega: VegaServiceNull):
@@ -264,19 +264,18 @@ def test_switch_teams(team_page: Page, vega: VegaServiceNull):
def test_leaderboard(competitions_page: Page, setup_teams_and_games):
team_name = setup_teams_and_games["team_name"]
competitions_page.reload()
competitions_page.pause()
expect(
competitions_page.get_by_test_id("rank-0").locator(".text-yellow-300")
).to_have_count(1)
expect(
competitions_page.get_by_test_id("rank-1").locator(".text-vega-clight-500")
).to_have_count(1)
expect(competitions_page.get_by_test_id("team-0")).to_have_text(team_name)
expect(competitions_page.get_by_test_id("team-1")).to_have_text(team_name)
expect(competitions_page.get_by_test_id("status-1")).to_have_text("Open")
# FIXME: the numbers are different we need to clarify this with the backend
# expect(competitions_page.get_by_test_id("earned-1")).to_have_text("160")
expect(competitions_page.get_by_test_id("games-1")).to_have_text("2")
expect(competitions_page.get_by_test_id("games-1")).to_have_text("1")
# TODO still odd that this is 0
expect(competitions_page.get_by_test_id("volume-0")).to_have_text("0")
+8
View File
@@ -0,0 +1,8 @@
import { ENV, Networks } from '@vegaprotocol/environment';
const TEAMS_STATS_EPOCHS_MAINNET = 30;
const TEAMS_STATS_EPOCHS_TESTNET = 192;
export const TEAMS_STATS_EPOCHS =
ENV.VEGA_ENV === Networks.MAINNET
? TEAMS_STATS_EPOCHS_MAINNET
: TEAMS_STATS_EPOCHS_TESTNET;
+2 -3
View File
@@ -7,8 +7,7 @@ import orderBy from 'lodash/orderBy';
import { removePaginationWrapper } from '@vegaprotocol/utils';
import { useEpochInfoQuery } from './__generated__/Epoch';
import { type ApolloError } from '@apollo/client';
const TAKE_EPOCHS = 30; // TODO: should this be DEFAULT_AGGREGATION_EPOCHS?
import { TEAMS_STATS_EPOCHS } from './constants';
const findTeam = (entities: GameFieldsFragment['entities'], teamId: string) => {
const team = entities.find(
@@ -45,7 +44,7 @@ export const useGames = (teamId?: string, epochFrom?: number): GamesData => {
let from = epochFrom;
if (!from && epochData) {
from = Number(epochData.epoch.id) - TAKE_EPOCHS;
from = Number(epochData.epoch.id) - TEAMS_STATS_EPOCHS;
if (from < 1) from = 1; // make sure it's not negative
}
+2 -2
View File
@@ -5,7 +5,7 @@ import {
type TeamRefereeFieldsFragment,
type TeamMemberStatsFieldsFragment,
} from './__generated__/Team';
import { DEFAULT_AGGREGATION_EPOCHS } from './use-teams';
import { TEAMS_STATS_EPOCHS } from './constants';
export type Team = TeamFieldsFragment;
export type TeamStats = TeamStatsFieldsFragment;
@@ -22,7 +22,7 @@ export const useTeam = (teamId?: string, partyId?: string) => {
variables: {
teamId: teamId || '',
partyId,
aggregationEpochs: DEFAULT_AGGREGATION_EPOCHS,
aggregationEpochs: TEAMS_STATS_EPOCHS,
},
skip: !teamId,
fetchPolicy: 'cache-and-network',
+2 -4
View File
@@ -4,9 +4,7 @@ import { useTeamsQuery } from './__generated__/Teams';
import { useTeamsStatisticsQuery } from './__generated__/TeamsStatistics';
import compact from 'lodash/compact';
import { type TeamStatsFieldsFragment } from './__generated__/Team';
// 192
export const DEFAULT_AGGREGATION_EPOCHS = 192;
import { TEAMS_STATS_EPOCHS } from './constants';
const EMPTY_STATS: Partial<TeamStatsFieldsFragment> = {
totalQuantumVolume: '0',
@@ -16,7 +14,7 @@ const EMPTY_STATS: Partial<TeamStatsFieldsFragment> = {
quantumRewards: [],
};
export const useTeams = (aggregationEpochs = DEFAULT_AGGREGATION_EPOCHS) => {
export const useTeams = (aggregationEpochs = TEAMS_STATS_EPOCHS) => {
const {
data: teamsData,
loading: teamsLoading,
@@ -71,7 +71,7 @@ function waitForStake(vegaPublicKey: string) {
let tick = 1;
const interval = setInterval(async () => {
log(`confirming stake (attempt: ${tick})`);
if (tick >= 30) {
if (tick >= 90) {
clearInterval(interval);
reject(new Error('stake link never seen'));
}
@@ -25,7 +25,7 @@ export const addCreateMarket = () => {
cy.highlight('creating market on capsule environment');
cy.wrap(createMarket(config), {
timeout: 5 * 60 * 1000,
timeout: 9 * 60 * 1000,
})
// register market list result so it can be retrieved in tests later
.as('markets');
@@ -111,7 +111,7 @@ export const addValidatorsSelfDelegate = () => {
String(node0ApiToken),
String(node0Id)
),
{ timeout: 60000 }
{ timeout: 90000 }
);
// Self delegating Node 1 wallet
cy.get('@node1PubKey').then((node1PubKey) => {
@@ -124,7 +124,7 @@ export const addValidatorsSelfDelegate = () => {
String(node1ApiToken),
String(node1Id)
),
{ timeout: 60000 }
{ timeout: 90000 }
);
});
});
+3
View File
@@ -21,6 +21,7 @@
"Ethereum Oracle": "Ethereum Oracle",
"every {{duration}}": "every {{duration}}",
"every {{duration}} from {{initialTime}}": "every {{duration}} from {{initialTime}}",
"Factor applied to funding-rates. This scales the impact that spot price deviations have on funding payments.": "Factor applied to funding-rates. This scales the impact that spot price deviations have on funding payments.",
"Fees paid to validators as a reward for running the infrastructure of the network.": "Fees paid to validators as a reward for running the infrastructure of the network.",
"Filters": "Filters",
"For liquidity orders to count towards a commitment, they must be within the liquidity monitoring bounds.": "For liquidity orders to count towards a commitment, they must be within the liquidity monitoring bounds.",
@@ -44,6 +45,7 @@
"Liquidity portion of the fee is paid to liquidity providers, and is transferred to the liquidity fee pool for the market.": "Liquidity portion of the fee is paid to liquidity providers, and is transferred to the liquidity fee pool for the market.",
"Liquidity price range": "Liquidity price range",
"Liquidity SLA protocol": "Liquidity SLA protocol",
"Lower bound for the funding-rate such that the funding-rate will never be lower than this value.": "Lower bound for the funding-rate such that the funding-rate will never be lower than this value.",
"Maker portion of the fee is transferred to the non-aggressive, or passive party in the trade (the maker, as opposed to the taker).": "Maker portion of the fee is transferred to the non-aggressive, or passive party in the trade (the maker, as opposed to the taker).",
"Margin scaling factors": "Margin scaling factors",
"Market": "Market",
@@ -138,6 +140,7 @@
"This public key's proofs have not been verified yet, or no proofs have been provided yet.": "This public key's proofs have not been verified yet, or no proofs have been provided yet.",
"Time horizon of the price projection in seconds.": "Time horizon of the price projection in seconds.",
"Updated": "Updated",
"Upper bound for the funding-rate such that the funding-rate will never be higher than this value.": "Upper bound for the funding-rate such that the funding-rate will never be higher than this value.",
"Used to calculate the penalty to liquidity providers when they cannot support their open position with the assets in their margin and general accounts. This is a network parameter.": "Used to calculate the penalty to liquidity providers when they cannot support their open position with the assets in their margin and general accounts. This is a network parameter.",
"Verified since {{lastVerified}}": "Verified since {{lastVerified}}",
"verifyProofs_one": "Verify {{count}} proof of ownership",
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -112,6 +112,9 @@ fragment Future on Future {
fragment Perpetual on Perpetual {
quoteName
fundingRateScalingFactor
fundingRateLowerBound
fundingRateUpperBound
settlementAsset {
id
symbol
File diff suppressed because one or more lines are too long
@@ -181,7 +181,10 @@ export const MarketInfoAccordion = ({
itemId="funding"
title={t('Funding')}
content={
<FundingInfoPanel dataSource={settlementScheduleDataSource} />
<FundingInfoPanel
dataSource={settlementScheduleDataSource}
market={market}
/>
}
/>
)}
@@ -84,6 +84,7 @@ import type { DataSourceFragment } from './__generated__/MarketInfo';
import { formatDuration } from 'date-fns';
import * as AccordionPrimitive from '@radix-ui/react-accordion';
import { useT } from '../../use-t';
import { isPerpetual } from '../../product';
type MarketInfoProps = {
market: MarketInfo;
@@ -920,8 +921,8 @@ export const EthOraclePanel = ({ sourceType }: { sourceType: EthCallSpec }) => {
<>
<MarketInfoTable key={i} data={filter.key} />
<h3 className={header}>{t('Conditions')}</h3>
{filter.conditions?.map((condition) => (
<span>
{filter.conditions?.map((condition, i) => (
<span key={i}>
{ConditionOperatorMapping[condition.operator]} {condition.value}
</span>
))}
@@ -1149,8 +1150,10 @@ export const LiquidityInfoPanel = ({ market, children }: MarketInfoProps) => {
export const FundingInfoPanel = ({
dataSource,
market,
}: {
dataSource: DataSourceFragment;
market: MarketInfo;
}) => {
const t = useT();
const sourceType = dataSource.data.sourceType.sourceType;
@@ -1167,12 +1170,30 @@ export const FundingInfoPanel = ({
hours,
minutes,
});
return initial
? t('every {{duration}} from {{initialTime}}', {
duration,
initialTime: getDateTimeFormat().format(new Date(initial * 1000)),
})
: t('every {{duration}}', { duration });
const { product } = market.tradableInstrument.instrument;
return (
<>
<p
className="first-letter:uppercase text-x;w
"
>
{initial
? t('every {{duration}} from {{initialTime}}', {
duration,
initialTime: getDateTimeFormat().format(new Date(initial * 1000)),
})
: t('every {{duration}}', { duration })}
</p>
<MarketInfoTable
data={{
rateScalingFactor:
isPerpetual(product) && product.fundingRateScalingFactor,
rateLowerBound: isPerpetual(product) && product.fundingRateLowerBound,
rateUpperBound: isPerpetual(product) && product.fundingRateUpperBound,
}}
/>
</>
);
};
export const OracleInfoPanel = ({
@@ -157,5 +157,14 @@ export const useTooltipMapping: () => Record<string, ReactNode> = () => {
feeConstant: t(
'The constant liquidity fee used when using the constant fee method .'
),
rateScalingFactor: t(
'Factor applied to funding-rates. This scales the impact that spot price deviations have on funding payments.'
),
rateLowerBound: t(
'Lower bound for the funding-rate such that the funding-rate will never be lower than this value.'
),
rateUpperBound: t(
'Upper bound for the funding-rate such that the funding-rate will never be higher than this value.'
),
};
};
+13 -9
View File
@@ -3831,6 +3831,7 @@ export type PartytradesConnectionArgs = {
export type PartytransfersConnectionArgs = {
direction?: InputMaybe<TransferDirection>;
fromEpoch?: InputMaybe<Scalars['Int']>;
gameId?: InputMaybe<Scalars['ID']>;
isReward?: InputMaybe<Scalars['Boolean']>;
pagination?: InputMaybe<Pagination>;
scope?: InputMaybe<TransferScope>;
@@ -4047,11 +4048,11 @@ export type Perpetual = {
/** Data source specification describing the data source for settlement schedule */
dataSourceSpecForSettlementSchedule: DataSourceSpec;
/** Lower bound for the funding-rate such that the funding-rate will never be lower than this value */
fundingRateLowerBound: Scalars['String'];
fundingRateLowerBound?: Maybe<Scalars['String']>;
/** Factor applied to funding-rates. This scales the impact that spot price deviations have on funding payments */
fundingRateScalingFactor: Scalars['String'];
fundingRateScalingFactor?: Maybe<Scalars['String']>;
/** Upper bound for the funding-rate such that the funding-rate will never be higher than this value */
fundingRateUpperBound: Scalars['String'];
fundingRateUpperBound?: Maybe<Scalars['String']>;
/** Continuously compounded interest rate used in funding rate calculation, in the range [-1, 1] */
interestRate: Scalars['String'];
/** Optional configuration driving the internal composite price calculation for perpetual product */
@@ -4104,11 +4105,11 @@ export type PerpetualProduct = {
/** Data source specification describing the data source for settlement schedule */
dataSourceSpecForSettlementSchedule: DataSourceDefinition;
/** Lower bound for the funding-rate such that the funding-rate will never be lower than this value */
fundingRateLowerBound: Scalars['String'];
fundingRateLowerBound?: Maybe<Scalars['String']>;
/** Factor applied to funding-rates. This scales the impact that spot price deviations have on funding payments. */
fundingRateScalingFactor: Scalars['String'];
fundingRateScalingFactor?: Maybe<Scalars['String']>;
/** Upper bound for the funding-rate such that the funding-rate will never be higher than this value */
fundingRateUpperBound: Scalars['String'];
fundingRateUpperBound?: Maybe<Scalars['String']>;
/** Continuously compounded interest rate used in funding rate calculation, in the range [-1, 1] */
interestRate: Scalars['String'];
/** Controls how much the upcoming funding payment liability contributes to party's margin, in the range [0, 1] */
@@ -5159,6 +5160,8 @@ export type QuerygamesArgs = {
epochTo?: InputMaybe<Scalars['Int']>;
gameId?: InputMaybe<Scalars['ID']>;
pagination?: InputMaybe<Pagination>;
partyId?: InputMaybe<Scalars['ID']>;
teamId?: InputMaybe<Scalars['ID']>;
};
@@ -5464,6 +5467,7 @@ export type QuerytransferArgs = {
export type QuerytransfersConnectionArgs = {
direction?: InputMaybe<TransferDirection>;
fromEpoch?: InputMaybe<Scalars['Int']>;
gameId?: InputMaybe<Scalars['ID']>;
isReward?: InputMaybe<Scalars['Boolean']>;
pagination?: InputMaybe<Pagination>;
partyId?: InputMaybe<Scalars['ID']>;
@@ -7099,11 +7103,11 @@ export type UpdatePerpetualProduct = {
/** Data source specification describing the data source for settlement schedule */
dataSourceSpecForSettlementSchedule: DataSourceDefinition;
/** Lower bound for the funding-rate such that the funding-rate will never be lower than this value */
fundingRateLowerBound: Scalars['String'];
fundingRateLowerBound?: Maybe<Scalars['String']>;
/** Factor applied to funding-rates. This scales the impact that spot price deviations have on funding payments. */
fundingRateScalingFactor: Scalars['String'];
fundingRateScalingFactor?: Maybe<Scalars['String']>;
/** Upper bound for the funding-rate such that the funding-rate will never be higher than this value */
fundingRateUpperBound: Scalars['String'];
fundingRateUpperBound?: Maybe<Scalars['String']>;
/** Continuously compounded interest rate used in funding rate calculation, in the range [-1, 1] */
interestRate: Scalars['String'];
/** Controls how much the upcoming funding payment liability contributes to party's margin, in the range [0, 1] */
+1
View File
@@ -175,6 +175,7 @@
},
"network_parameters": {
"blockchains.ethereumConfig": "{\"network_id\": \"{{ .NetworkID }}\", \"chain_id\": \"{{ .ChainID }}\", \"collateral_bridge_contract\": { \"address\": \"{{.GetEthContractAddr "erc20_bridge_1"}}\" }, \"confirmations\": 3, \"staking_bridge_contract\": { \"address\": \"{{.GetEthContractAddr "staking_bridge"}}\", \"deployment_block_height\": 0}, \"token_vesting_contract\": { \"address\": \"{{.GetEthContractAddr "erc20_vesting"}}\", \"deployment_block_height\": 0 }, \"multisig_control_contract\": { \"address\": \"{{.GetEthContractAddr "MultisigControl"}}\", \"deployment_block_height\": 0 }}",
"blockchains.ethereumRpcAndEvmCompatDataSourcesConfig": "{\"configs\": []}",
"governance.proposal.asset.minClose": "2s",
"governance.proposal.asset.minEnact": "2s",
"governance.proposal.asset.requiredParticipation": "0.00000000000000000000000015",