chore(trading): fees e2e tests (#5496)

This commit is contained in:
Ben 2023-12-19 12:22:15 +00:00 committed by GitHub
parent 665ab6693a
commit 0af1d0ba82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 837 additions and 60 deletions

View File

@ -8,15 +8,18 @@ export const Card = ({
className, className,
loading = false, loading = false,
highlight = false, highlight = false,
testId,
}: { }: {
children: ReactNode; children: ReactNode;
title: string; title: string;
className?: string; className?: string;
loading?: boolean; loading?: boolean;
highlight?: boolean; highlight?: boolean;
testId?: string;
}) => { }) => {
return ( return (
<div <div
data-testid={testId}
className={classNames( className={classNames(
'bg-vega-clight-800 dark:bg-vega-cdark-800 col-span-full p-0.5 lg:col-auto', 'bg-vega-clight-800 dark:bg-vega-cdark-800 col-span-full p-0.5 lg:col-auto',
'rounded-lg', 'rounded-lg',

View File

@ -84,7 +84,10 @@ export const FeesContainer = () => {
); );
return ( return (
<div className="grid auto-rows-min grid-cols-4 gap-3"> <div
className="grid auto-rows-min grid-cols-4 gap-3"
data-testid="fees-container"
>
{isConnected && ( {isConnected && (
<> <>
<Card <Card
@ -124,7 +127,10 @@ export const FeesContainer = () => {
windowLength={volumeDiscountWindowLength} windowLength={volumeDiscountWindowLength}
/> />
) : ( ) : (
<p className="text-muted pt-3 text-sm"> <p
className="text-muted pt-3 text-sm"
data-testid="no-volume-discount"
>
{t('No volume discount program active')} {t('No volume discount program active')}
</p> </p>
)} )}
@ -133,17 +139,22 @@ export const FeesContainer = () => {
title={t('Referral benefits')} title={t('Referral benefits')}
className="sm:col-span-2" className="sm:col-span-2"
loading={loading} loading={loading}
data-testid="referral-benefits-card"
> >
{isReferrer ? ( {isReferrer ? (
<ReferrerInfo code={code} /> <ReferrerInfo code={code} data-testid="referrer-info" />
) : isReferralProgramRunning ? ( ) : isReferralProgramRunning ? (
<ReferralBenefits <ReferralBenefits
setRunningNotionalTakerVolume={referralVolumeInWindow} setRunningNotionalTakerVolume={referralVolumeInWindow}
epochsInSet={epochsInSet} epochsInSet={epochsInSet}
epochs={referralDiscountWindowLength} epochs={referralDiscountWindowLength}
data-testid="referral-benefits"
/> />
) : ( ) : (
<p className="text-muted pt-3 text-sm"> <p
className="text-muted pt-3 text-sm"
data-testid="no-referral-program"
>
{t('No referral program active')} {t('No referral program active')}
</p> </p>
)} )}
@ -154,6 +165,7 @@ export const FeesContainer = () => {
title={t('Volume discount')} title={t('Volume discount')}
className="lg:col-span-full xl:col-span-2" className="lg:col-span-full xl:col-span-2"
loading={loading} loading={loading}
data-testid="volume-discount-card"
> >
<VolumeTiers <VolumeTiers
tiers={volumeTiers} tiers={volumeTiers}
@ -166,6 +178,7 @@ export const FeesContainer = () => {
title={t('Referral discount')} title={t('Referral discount')}
className="lg:col-span-full xl:col-span-2" className="lg:col-span-full xl:col-span-2"
loading={loading} loading={loading}
data-testid="referral-discount-card"
> >
<ReferralTiers <ReferralTiers
tiers={referralTiers} tiers={referralTiers}
@ -178,6 +191,7 @@ export const FeesContainer = () => {
title={t('Fees by market')} title={t('Fees by market')}
className="lg:col-span-full" className="lg:col-span-full"
loading={marketsLoading} loading={marketsLoading}
data-testid="fees-by-market-card"
> >
<MarketFees <MarketFees
markets={markets} markets={markets}
@ -245,7 +259,7 @@ export const TradingFees = ({
} }
return ( return (
<div className="pt-4"> <div className="pt-4" data-testid="trading-fees">
<div className="leading-none"> <div className="leading-none">
<p className="block text-3xl leading-none" data-testid="adjusted-fees"> <p className="block text-3xl leading-none" data-testid="adjusted-fees">
{minAdjustedTotal !== undefined && maxAdjustedTotal !== undefined {minAdjustedTotal !== undefined && maxAdjustedTotal !== undefined
@ -255,7 +269,7 @@ export const TradingFees = ({
: `${formatPercentage(adjustedTotal)}%`} : `${formatPercentage(adjustedTotal)}%`}
</p> </p>
<CardTable> <CardTable>
<tr className="text-default"> <tr className="text-default" data-testid="total-fee-before-discount">
<CardTableTH>{t('Total fee before discount')}</CardTableTH> <CardTableTH>{t('Total fee before discount')}</CardTableTH>
<CardTableTD> <CardTableTD>
{minTotal !== undefined && maxTotal !== undefined {minTotal !== undefined && maxTotal !== undefined
@ -265,7 +279,7 @@ export const TradingFees = ({
: `${formatPercentage(total.toNumber())}%`} : `${formatPercentage(total.toNumber())}%`}
</CardTableTD> </CardTableTD>
</tr> </tr>
<tr> <tr data-testid="infrastructure-fees">
<CardTableTH>{t('Infrastructure')}</CardTableTH> <CardTableTH>{t('Infrastructure')}</CardTableTH>
<CardTableTD> <CardTableTD>
{formatPercentage( {formatPercentage(
@ -274,14 +288,14 @@ export const TradingFees = ({
% %
</CardTableTD> </CardTableTD>
</tr> </tr>
<tr> <tr data-testid="maker-fees">
<CardTableTH>{t('Maker')}</CardTableTH> <CardTableTH>{t('Maker')}</CardTableTH>
<CardTableTD> <CardTableTD>
{formatPercentage(Number(params.market_fee_factors_makerFee))}% {formatPercentage(Number(params.market_fee_factors_makerFee))}%
</CardTableTD> </CardTableTD>
</tr> </tr>
{minLiq && maxLiq && ( {minLiq && maxLiq && (
<tr> <tr data-testid="liquidity-fees">
<CardTableTH>{t('Liquidity')}</CardTableTH> <CardTableTH>{t('Liquidity')}</CardTableTH>
<CardTableTD> <CardTableTD>
{formatPercentage(Number(minLiq.fees.factors.liquidityFee))}% {formatPercentage(Number(minLiq.fees.factors.liquidityFee))}%
@ -317,7 +331,7 @@ export const CurrentVolume = ({
const currentVolume = new BigNumber(windowLengthVolume); const currentVolume = new BigNumber(windowLengthVolume);
return ( return (
<div className="flex flex-col gap-3 pt-4"> <div className="flex flex-col gap-3 pt-4" data-testid="current-volume">
<CardStat <CardStat
value={ value={
currentVolume.isZero() currentVolume.isZero()
@ -327,11 +341,13 @@ export const CurrentVolume = ({
text={t('pastEpochs', 'Past {{count}} epochs', { text={t('pastEpochs', 'Past {{count}} epochs', {
count: windowLength, count: windowLength,
})} })}
testId="past-epochs-volume"
/> />
{requiredForNextTier.isGreaterThan(0) && ( {requiredForNextTier.isGreaterThan(0) && (
<CardStat <CardStat
value={formatNumber(requiredForNextTier)} value={formatNumber(requiredForNextTier)}
text={t('Required for next tier')} text={t('Required for next tier')}
testId="required-for-next-tier"
/> />
)} )}
</div> </div>
@ -349,7 +365,7 @@ const ReferralBenefits = ({
}) => { }) => {
const t = useT(); const t = useT();
return ( return (
<div className="flex flex-col gap-3 pt-4"> <div className="flex flex-col gap-3 pt-4" data-testid="referral-benefits">
<CardStat <CardStat
// all sets volume (not just current party) // all sets volume (not just current party)
value={formatNumber(setRunningNotionalTakerVolume)} value={formatNumber(setRunningNotionalTakerVolume)}
@ -360,8 +376,13 @@ const ReferralBenefits = ({
count: epochs, count: epochs,
} }
)} )}
testId="running-notional-taker-volume"
/>
<CardStat
value={epochsInSet}
text={t('epochs in referral set')}
testId="epochs-in-referral-set"
/> />
<CardStat value={epochsInSet} text={t('epochs in referral set')} />
</div> </div>
); );
}; };
@ -389,7 +410,7 @@ const TotalDiscount = ({
); );
return ( return (
<div className="pt-4"> <div className="pt-4" data-testid="total-discount-card-stats">
<CardStat <CardStat
description={ description={
<> <>
@ -399,9 +420,10 @@ const TotalDiscount = ({
} }
value={formatPercentage(totalDiscount) + '%'} value={formatPercentage(totalDiscount) + '%'}
highlight={true} highlight={true}
testId="total-discount"
/> />
<CardTable> <CardTable>
<tr> <tr data-testid="volume-discount-row">
<CardTableTH>{t('Volume discount')}</CardTableTH> <CardTableTH>{t('Volume discount')}</CardTableTH>
<CardTableTD> <CardTableTD>
{formatPercentage(volumeDiscount)}% {formatPercentage(volumeDiscount)}%
@ -415,7 +437,7 @@ const TotalDiscount = ({
)} )}
</CardTableTD> </CardTableTD>
</tr> </tr>
<tr> <tr data-testid="referral-discount-row">
<CardTableTH>{t('Referral discount')}</CardTableTH> <CardTableTH>{t('Referral discount')}</CardTableTH>
<CardTableTD> <CardTableTD>
{formatPercentage(referralDiscount)}% {formatPercentage(referralDiscount)}%
@ -461,29 +483,37 @@ const VolumeTiers = ({
<div> <div>
<Table> <Table>
<THead> <THead>
<tr> <Tr>
<Th>{t('Tier')}</Th> <Th data-testid="tier-header">{t('Tier')}</Th>
<Th>{t('Discount')}</Th> <Th data-testid="discount-header">{t('Discount')}</Th>
<Th>{t('Min. trading volume')}</Th> <Th data-testid="min-volume-header">{t('Min. trading volume')}</Th>
<Th> <Th data-testid="my-volume-header">
{t('myVolume', 'My volume (last {{count}} epochs)', { {t('myVolume', 'My volume (last {{count}} epochs)', {
count: windowLength, count: windowLength,
})} })}
</Th> </Th>
<Th /> <Th data-testid="actions-header" />
</tr> </Tr>
</THead> </THead>
<tbody> <tbody>
{Array.from(tiers).map((tier, i) => { {Array.from(tiers).map((tier, i) => {
const isUserTier = tierIndex === i; const isUserTier = tierIndex === i;
return ( return (
<Tr key={i}> <Tr key={i} data-testid={`tier-row-${i}`}>
<Td>{i + 1}</Td> <Td data-testid={`tier-value-${i}`}>{i + 1}</Td>
<Td>{formatPercentage(Number(tier.volumeDiscountFactor))}%</Td> <Td data-testid={`discount-value-${i}`}>
<Td>{formatNumber(tier.minimumRunningNotionalTakerVolume)}</Td> {formatPercentage(Number(tier.volumeDiscountFactor))}%
<Td>{isUserTier ? formatNumber(lastEpochVolume) : ''}</Td> </Td>
<Td>{isUserTier ? <YourTier /> : null}</Td> <Td data-testid={`min-volume-value-${i}`}>
{formatNumber(tier.minimumRunningNotionalTakerVolume)}
</Td>
<Td data-testid={`my-volume-value-${i}`}>
{isUserTier ? formatNumber(lastEpochVolume) : ''}
</Td>
<Td data-testid={`your-tier-${i}`}>
{isUserTier ? <YourTier /> : null}
</Td>
</Tr> </Tr>
); );
})} })}
@ -520,39 +550,53 @@ const ReferralTiers = ({
<div> <div>
<Table> <Table>
<THead> <THead>
<tr> <Tr>
<Th>{t('Tier')}</Th> <Th data-testid="tier-header">{t('Tier')}</Th>
<Th>{t('Discount')}</Th> <Th data-testid="discount-header">{t('Discount')}</Th>
<Th>{t('Min. trading volume')}</Th> <Th data-testid="min-volume-header">{t('Min. trading volume')}</Th>
<Th>{t('Required epochs')}</Th> <Th data-testid="required-epochs-header">{t('Required epochs')}</Th>
<Th /> <Th data-testid="extra-header" />
</tr> </Tr>
</THead> </THead>
<tbody> <tbody>
{Array.from(tiers).map((t, i) => { {Array.from(tiers).map((tier, i) => {
const isUserTier = tierIndex === i; const isUserTier = tierIndex === i;
const requiredVolume = Number(t.minimumRunningNotionalTakerVolume); const requiredVolume = Number(
tier.minimumRunningNotionalTakerVolume
);
let unlocksIn = null; let unlocksIn = null;
if ( if (
referralVolumeInWindow >= requiredVolume && referralVolumeInWindow >= requiredVolume &&
epochsInSet < t.minimumEpochs epochsInSet < tier.minimumEpochs
) { ) {
unlocksIn = ( unlocksIn = (
<span className="text-muted"> <span className="text-muted">
Unlocks in {t.minimumEpochs - epochsInSet} epochs Unlocks in {tier.minimumEpochs - epochsInSet} epochs
</span> </span>
); );
} }
return ( return (
<Tr key={i}> <Tr key={i} data-testid={`tier-row-${i}`}>
<Td>{i + 1}</Td> <Td data-testid={`tier-value-${i}`}>{i + 1}</Td>
<Td>{formatPercentage(Number(t.referralDiscountFactor))}%</Td> <Td data-testid={`discount-value-${i}`}>
<Td>{formatNumber(t.minimumRunningNotionalTakerVolume)}</Td> {formatPercentage(Number(tier.referralDiscountFactor))}%
<Td>{t.minimumEpochs}</Td> </Td>
<Td>{isUserTier ? <YourTier /> : unlocksIn}</Td> <Td data-testid={`min-volume-value-${i}`}>
{formatNumber(tier.minimumRunningNotionalTakerVolume)}
</Td>
<Td data-testid={`required-epochs-value-${i}`}>
{tier.minimumEpochs}
</Td>
<Td data-testid={`user-tier-or-unlocks-${i}`}>
{isUserTier ? (
<YourTier testId={`your-tier-${i}`} />
) : (
unlocksIn
)}
</Td>
</Tr> </Tr>
); );
})} })}
@ -562,11 +606,18 @@ const ReferralTiers = ({
); );
}; };
const YourTier = () => { interface YourTierProps {
testId?: string;
}
const YourTier = ({ testId }: YourTierProps) => {
const t = useT(); const t = useT();
return ( return (
<span className="bg-rainbow whitespace-nowrap rounded-xl px-4 py-1.5 text-white"> <span
className="bg-rainbow whitespace-nowrap rounded-xl px-4 py-1.5 text-white"
data-testid={testId}
>
{t('Your tier')} {t('Your tier')}
</span> </span>
); );

View File

@ -3,21 +3,31 @@ import type { ReactNode } from 'react';
const cellClass = 'px-4 py-2 text-xs font-normal text-left last:text-right'; const cellClass = 'px-4 py-2 text-xs font-normal text-left last:text-right';
export const Th = ({ children }: { children?: ReactNode }) => { export const Th = ({ children, ...props }: { children?: ReactNode }) => {
return ( return (
<th className={classNames(cellClass, 'text-secondary leading-none py-3')}> <th
className={classNames(cellClass, 'text-secondary leading-none py-3')}
{...props}
>
{children} {children}
</th> </th>
); );
}; };
export const Td = ({ children }: { children?: ReactNode }) => { export const Td = ({ children, ...props }: { children?: ReactNode }) => {
return <th className={cellClass}>{children}</th>; return (
<th className={cellClass} {...props}>
{children}
</th>
);
}; };
export const Tr = ({ children }: { children?: ReactNode }) => { export const Tr = ({ children, ...props }: { children?: ReactNode }) => {
return ( return (
<tr className="hover:bg-vega-clight-600 dark:hover:bg-vega-cdark-700"> <tr
className="hover:bg-vega-clight-600 dark:hover:bg-vega-cdark-700"
{...props}
>
{children} {children}
</tr> </tr>
); );

View File

@ -24,6 +24,12 @@ poetry shell
5. **Install python dependencies** 5. **Install python dependencies**
To make sure you are on the latest version of our market-sim branch.
```bash
poetry update vega-sim
```
```bash ```bash
poetry install poetry install
``` ```

View File

@ -55,14 +55,14 @@ def change_keys(page: Page, vega: VegaServiceNull, key_name):
page.reload() page.reload()
def forward_time(vega: VegaServiceNull, forward_epoch: bool = False): def forward_time(vega:VegaServiceNull, forward_epoch: bool = False):
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
if forward_epoch: if forward_epoch:
next_epoch(vega) next_epoch(vega)
# This is for when the element will initially load but contain an outdated value. It will wait for the element to contain the expected text, returning False after a timeout or exception # This is for when the element will initially load but contain an outdated value. It will wait for the element to contain the expected text, returning False after a timeout or exception
def selector_contains_text(page: Page, selector, expected_text, timeout=5000): def selector_contains_text(page: Page, selector, expected_text, timeout=5000):
try: try:
@ -71,3 +71,4 @@ def selector_contains_text(page: Page, selector, expected_text, timeout=5000):
return True return True
except: except:
return False return False

View File

@ -245,3 +245,11 @@ def setup_perps_market(
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
return market_id return market_id
def market_exists(vega: VegaService, market_id: str):
if market_id is None:
return False
all_markets = vega.all_markets()
market_ids = [market.id for market in all_markets]
return market_id in market_ids

View File

@ -0,0 +1,682 @@
import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from actions.vega import submit_order
from wallet_config import MM_WALLET
from conftest import init_vega, init_page, auth_setup
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"
YOUR_TIER_0 = "your-tier-0"
YOUR_TIER_1 = "your-tier-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"
ROW_LOCATOR = ".ag-center-cols-container .ag-row"
# Col-Ids:
COL_INSTRUMENT_CODE = '[col-id="market.tradableInstrument.instrument.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:
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:
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:
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:
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:
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: VegaService, 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: VegaService, 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: VegaService):
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-tier-0"),
(2, "volume", "my-volume-value-1", "206", "your-tier-1"),
(1, "referral", "my-volume-value-0", "103", "your-tier-0"),
(2, "referral", "my-volume-value-1", "206", "your-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)).to_be_visible()
expect(page.get_by_test_id(your_tier)).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")
row = page.locator(ROW_LOCATOR)
expect(row.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_INSTRUMENT_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_SIZE)).to_have_text(size)
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text(price_1)
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_INSTRUMENT_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_SIZE)).to_have_text(size)
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text(price_1)
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
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
f"If the market was activeThe maker will receive the maker fee.If the market is active the maker will pay zero 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
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.Infrastructure fee{infra_fee} tDAILiquidity fee0.00 tDAIMaker fee{maker_fee} tDAITotal fees{total_fee} tDAI"
)

View File

@ -76,9 +76,14 @@ export const DealTicketFeeDetails = ({
<KeyValue <KeyValue
label={ label={
<> <>
{t('Fees')} <span data-testid="fees-text">{t('Fees')}</span>
{totalDiscountFactor !== '0' ? ( {totalDiscountFactor !== '0' ? (
<Pill size="xxs" intent={Intent.Info} className="ml-1"> <Pill
size="xxs"
intent={Intent.Info}
className="ml-1"
data-testid="discount-pill"
>
{formatNumberPercentage( {formatNumberPercentage(
new BigNumber(totalDiscountFactor).multipliedBy(100) new BigNumber(totalDiscountFactor).multipliedBy(100)
)} )}

View File

@ -23,19 +23,23 @@ const FeesBreakdownItem = ({
value, value,
symbol, symbol,
decimals, decimals,
testId,
}: { }: {
label: string; label: string;
factor?: string | number; factor?: string | number;
value: string; value: string;
symbol?: string; symbol?: string;
decimals: number; decimals: number;
testId?: string;
}) => ( }) => (
<> <>
<dt className="col-span-2">{label}</dt> <dt className="col-span-2" data-testid={`${testId}-label`}>
<dd className="text-right col-span-1"> {label}
</dt>
<dd className="text-right col-span-1" data-testid={`${testId}-factor`}>
{factor ? formatNumberPercentage(new BigNumber(factor).times(100)) : ''} {factor ? formatNumberPercentage(new BigNumber(factor).times(100)) : ''}
</dd> </dd>
<dd className="text-right col-span-3"> <dd className="text-right col-span-3" data-testid={`${testId}-value`}>
{formatValue(value, decimals)} {symbol || ''} {formatValue(value, decimals)} {symbol || ''}
</dd> </dd>
</> </>
@ -73,6 +77,7 @@ export const FeesBreakdown = ({
value={fees.infrastructureFee} value={fees.infrastructureFee}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
testId="infrastructure-fee"
/> />
<FeesBreakdownItem <FeesBreakdownItem
@ -81,6 +86,7 @@ export const FeesBreakdown = ({
value={fees.liquidityFee} value={fees.liquidityFee}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
testId="liquidity-fee"
/> />
<FeesBreakdownItem <FeesBreakdownItem
@ -89,6 +95,7 @@ export const FeesBreakdown = ({
value={fees.makerFee} value={fees.makerFee}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
testId="maker-fee"
/> />
{totalDiscount && totalDiscount !== '0' ? ( {totalDiscount && totalDiscount !== '0' ? (
<> <>
@ -100,6 +107,7 @@ export const FeesBreakdown = ({
} }
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
testId="subtotal-fee"
/> />
<div className="col-span-6 mt-2"></div> <div className="col-span-6 mt-2"></div>
<FeesBreakdownItem <FeesBreakdownItem
@ -108,12 +116,14 @@ export const FeesBreakdown = ({
value={`-${totalDiscount}`} value={`-${totalDiscount}`}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
testId="discount-fee"
/> />
<FeesBreakdownItem <FeesBreakdownItem
label={t('Total')} label={t('Total')}
value={discountedTotalFeeAmount} value={discountedTotalFeeAmount}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
testId="total-fee"
/> />
</> </>
) : ( ) : (
@ -127,6 +137,7 @@ export const FeesBreakdown = ({
value={totalFeeAmount} value={totalFeeAmount}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
testId="full-total-fee"
/> />
</> </>
)} )}