+
{title}
-
{children}
+
+ {children}
+
{description && (
{description}
diff --git a/apps/trading/e2e/actions/utils.py b/apps/trading/e2e/actions/utils.py
index 8dd831f14..94b5a4d63 100644
--- a/apps/trading/e2e/actions/utils.py
+++ b/apps/trading/e2e/actions/utils.py
@@ -6,23 +6,27 @@ from typing import Optional
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
ASSET_NAME = "tDAI"
+
def wait_for_toast_confirmation(page: Page, timeout: int = 30000):
page.wait_for_function("""
document.querySelector('[data-testid="toast-content"]') &&
document.querySelector('[data-testid="toast-content"]').innerText.includes('AWAITING CONFIRMATION')
""", timeout=timeout)
+
def create_and_faucet_wallet(
vega: VegaServiceNull,
wallet: WalletConfig,
symbol: Optional[str] = None,
amount: float = 1e4,
-
+
):
- asset_id = vega.find_asset_id(symbol=symbol if symbol is not None else ASSET_NAME)
+ asset_id = vega.find_asset_id(
+ symbol=symbol if symbol is not None else ASSET_NAME)
vega.create_key(wallet.name)
vega.mint(wallet.name, asset_id, amount)
+
def next_epoch(vega: VegaServiceNull):
forwards = 0
epoch_seq = vega.statistics().epoch_seq
@@ -36,13 +40,34 @@ def next_epoch(vega: VegaServiceNull):
vega.wait_fn(1)
vega.wait_for_total_catchup()
+
def truncate_middle(market_id, start=6, end=4):
if len(market_id) < 11:
return market_id
return market_id[:start] + '\u2026' + market_id[-end:]
-def change_keys(page: Page, vega:VegaServiceNull, key_name):
+
+def change_keys(page: Page, vega: VegaServiceNull, key_name):
page.get_by_test_id("manage-vega-wallet").click()
page.get_by_test_id("key-" + vega.wallet.public_key(key_name)).click()
- page.click(f'data-testid=key-{vega.wallet.public_key(key_name)} >> .inline-flex')
+ page.click(
+ f'data-testid=key-{vega.wallet.public_key(key_name)} >> .inline-flex')
page.reload()
+
+
+def forward_time(vega: VegaServiceNull, forward_epoch: bool = False):
+ vega.wait_fn(1)
+ vega.wait_for_total_catchup()
+
+ if forward_epoch:
+ 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
+def selector_contains_text(page: Page, selector, expected_text, timeout=5000):
+ try:
+ page.wait_for_selector(
+ f'{selector} >> text={expected_text}', timeout=timeout)
+ return True
+ except:
+ return False
diff --git a/apps/trading/e2e/actions/vega.py b/apps/trading/e2e/actions/vega.py
index ff8f83a29..1b99202e8 100644
--- a/apps/trading/e2e/actions/vega.py
+++ b/apps/trading/e2e/actions/vega.py
@@ -1,6 +1,7 @@
from typing import List, Tuple, Optional
from vega_sim.service import VegaService, PeggedOrder
+
def submit_order(
vega: VegaService,
wallet_name: str,
@@ -35,7 +36,7 @@ def submit_multiple_orders(
submit_order(vega, wallet_name, market_id, side, volume, price)
-def submit_liquidity(vega: VegaService, wallet_name: str, market_id: str):
+def submit_liquidity(vega: VegaService, wallet_name: str, market_id: str, buy_vol=99, sell_vol=99, custom_price=None):
vega.submit_simple_liquidity(
key_name=wallet_name,
market_id=market_id,
@@ -51,7 +52,7 @@ def submit_liquidity(vega: VegaService, wallet_name: str, market_id: str):
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_MID", offset=1),
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
- volume=99,
+ volume=buy_vol,
)
vega.submit_order(
market_id=market_id,
@@ -61,5 +62,5 @@ def submit_liquidity(vega: VegaService, wallet_name: str, market_id: str):
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_MID", offset=1),
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
- volume=99,
- )
\ No newline at end of file
+ volume=sell_vol,
+ )
diff --git a/apps/trading/e2e/fixtures/market.py b/apps/trading/e2e/fixtures/market.py
index 244787250..f49a9f255 100644
--- a/apps/trading/e2e/fixtures/market.py
+++ b/apps/trading/e2e/fixtures/market.py
@@ -8,12 +8,17 @@ logger = logging.getLogger()
mint_amount: float = 10e5
market_name = "BTC:DAI_2023"
+default_sell_orders = [[1, 110], [1, 105]]
+default_buy_orders = [[1, 90], [1, 95]]
+
+
def setup_simple_market(
vega: VegaService,
approve_proposal=True,
custom_market_name=market_name,
custom_asset_name="tDAI",
custom_asset_symbol="tDAI",
+ custom_quantum=1
):
for wallet in wallets:
vega.create_key(wallet.name)
@@ -37,6 +42,7 @@ def setup_simple_market(
symbol=custom_asset_symbol,
decimals=5,
max_faucet_amount=1e10,
+ quantum=custom_quantum,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -111,16 +117,17 @@ def setup_simple_successor_market(
return market_id
-def setup_opening_auction_market(vega: VegaService, market_id: str = None, **kwargs):
- if market_id is None or market_id not in vega.all_markets():
+def setup_opening_auction_market(vega: VegaService, market_id: str = None, buy_orders=default_buy_orders, sell_orders=default_sell_orders, add_liquidity=True, **kwargs):
+ if not market_exists(vega, market_id):
market_id = setup_simple_market(vega, **kwargs)
- submit_liquidity(vega, MM_WALLET.name, market_id)
+ if add_liquidity:
+ submit_liquidity(vega, MM_WALLET.name, market_id)
submit_multiple_orders(
- vega, MM_WALLET.name, market_id, "SIDE_SELL", [[1, 110], [1, 105]]
+ vega, MM_WALLET.name, market_id, "SIDE_SELL", sell_orders
)
submit_multiple_orders(
- vega, MM_WALLET2.name, market_id, "SIDE_BUY", [[1, 90], [1, 95]]
+ vega, MM_WALLET2.name, market_id, "SIDE_BUY", buy_orders
)
vega.forward("10s")
@@ -130,11 +137,22 @@ def setup_opening_auction_market(vega: VegaService, market_id: str = None, **kwa
return market_id
-def setup_continuous_market(vega: VegaService, market_id: str = None, **kwargs):
- if market_id is None or market_id not in vega.all_markets():
- market_id = setup_opening_auction_market(vega, **kwargs)
+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
- submit_order(vega, "Key 1", market_id, "SIDE_BUY", 1, 110)
+
+# Add sell orders and buy orders to put on the book
+def setup_continuous_market(vega: VegaService, market_id: str = None, buy_orders=default_buy_orders, sell_orders=default_sell_orders, add_liquidity=True, **kwargs):
+ if not market_exists(vega, market_id) or buy_orders != default_buy_orders or sell_orders != default_sell_orders:
+ market_id = setup_opening_auction_market(
+ vega, market_id, buy_orders, sell_orders, add_liquidity, **kwargs)
+
+ submit_order(vega, "Key 1", market_id, "SIDE_BUY",
+ sell_orders[0][0], sell_orders[0][1])
vega.forward("10s")
vega.wait_fn(1)
@@ -142,6 +160,7 @@ def setup_continuous_market(vega: VegaService, market_id: str = None, **kwargs):
return market_id
+
def setup_perps_market(
vega: VegaService,
custom_asset_name="tDAI",
@@ -210,7 +229,7 @@ def setup_perps_market(
settlement_data_key=TERMINATE_WALLET.name,
funding_payment_frequency_in_seconds=10,
market_decimals=5,
- )
+ )
vega.wait_for_total_catchup()
submit_liquidity(vega, MM_WALLET.name, market_id)
@@ -225,4 +244,4 @@ def setup_perps_market(
vega.wait_fn(1)
vega.wait_for_total_catchup()
- return market_id
\ No newline at end of file
+ return market_id
diff --git a/apps/trading/e2e/tests/referrals/test_referrals.py b/apps/trading/e2e/tests/referrals/test_referrals.py
new file mode 100644
index 000000000..33ae3208e
--- /dev/null
+++ b/apps/trading/e2e/tests/referrals/test_referrals.py
@@ -0,0 +1,175 @@
+import pytest
+from playwright.sync_api import Page, expect
+from vega_sim.service import VegaService
+from conftest import init_vega
+from fixtures.market import setup_continuous_market, setup_simple_market
+from actions.utils import change_keys, create_and_faucet_wallet, forward_time, selector_contains_text
+from actions.vega import submit_order, submit_liquidity
+from wallet_config import MM_WALLET, PARTY_A, PARTY_B
+
+SELL_ORDERS = [[1, 111], [1, 111], [1, 112], [1, 112], [
+ 1, 113], [1, 113], [1, 114], [1, 114], [1, 115], [1, 115]]
+BUY_ORDERS = [[1, 106], [1, 107], [1, 108]]
+
+
+@pytest.fixture(scope="module")
+def vega(request):
+ with init_vega(request) as vega:
+ yield vega
+
+
+@pytest.fixture(scope="module")
+def continuous_market(vega):
+ market = setup_simple_market(vega, custom_quantum=100000)
+ return setup_continuous_market(vega, market, BUY_ORDERS, SELL_ORDERS, add_liquidity=False)
+
+
+def generate_referrer_expected_value_dic(expected_base_commission, expected_staking_multiplier, expected_final_commission_rate, expected_volume, expected_num_traders, expected_total_commission):
+ return {
+ '[data-testid=my-volume-value]': expected_volume,
+ '[data-testid=total-commission-value]': expected_total_commission,
+ '[data-testid=base-commission-rate-value]': expected_base_commission,
+ '[data-testid=number-of-traders-value]': expected_num_traders,
+ '[data-testid=final-commission-rate-value]': expected_final_commission_rate,
+ '[data-testid=staking-multiplier-value]': expected_staking_multiplier
+ }
+
+
+def generate_referral_expected_value_dic(expected_volume, expected_tier, expected_discount, expected_epochs, expected_epochs_to_next_tier):
+ return {
+ '[data-testid=combined-volume-value]': expected_volume,
+ '[data-testid=current-tier-value]': expected_tier,
+ '[data-testid=discount-value]': expected_discount,
+ '[data-testid=epochs-in-set-value]': expected_epochs,
+ '[data-testid=epochs-to-next-tier-value]': expected_epochs_to_next_tier
+ }
+
+
+def check_tile_values(page: Page, expected_results: dict):
+ if "referrals" in page.url:
+ page.reload()
+ else:
+ page.goto("/#/referrals/")
+
+ for selector, expected_text in expected_results.items():
+ assert selector_contains_text(
+ page, selector, expected_text), f"Expected text '{expected_text}' not found in selector '{selector}'"
+
+
+def create_benefit_tier(minimum_running_notional_taker_volume, minimum_epochs, referral_reward_factor, referral_discount_factor):
+ return {
+ "minimum_running_notional_taker_volume": minimum_running_notional_taker_volume,
+ "minimum_epochs": minimum_epochs,
+ "referral_reward_factor": referral_reward_factor,
+ "referral_discount_factor": referral_discount_factor,
+ }
+
+
+def create_staking_tier(minimum_staked_tokens, referral_reward_multiplier):
+ return {
+ "minimum_staked_tokens": minimum_staked_tokens,
+ "referral_reward_multiplier": referral_reward_multiplier,
+ }
+
+
+def setup_market_and_referral_scheme(vega: VegaService, continuous_market: str, page: Page):
+ page.goto(f"/#/markets/{continuous_market}")
+
+ create_and_faucet_wallet(vega=vega, wallet=PARTY_A)
+ create_and_faucet_wallet(vega=vega, wallet=PARTY_B)
+ forward_time(vega)
+
+ benefit_tiers = []
+ staking_tiers = []
+ for i in range(1, 4):
+ benefit_tiers.append(create_benefit_tier(
+ i * 100, i, i * 0.01, i * 0.01))
+ staking_tiers.append(create_staking_tier(
+ i * 100, i))
+
+ vega.update_referral_program(
+ proposal_key=MM_WALLET.name,
+ benefit_tiers=benefit_tiers,
+ staking_tiers=staking_tiers,
+ window_length=1,
+ )
+ forward_time(vega, True)
+
+ vega.create_referral_set(key_name=PARTY_A.name)
+ forward_time(vega, True)
+
+ referral_set_id = list(vega.list_referral_sets().keys())[0]
+ vega.apply_referral_code(key_name=PARTY_B.name, id=referral_set_id)
+
+ tdai_id = vega.find_asset_id(symbol="tDAI")
+ vega.mint(
+ "Key 1",
+ asset=tdai_id,
+ amount=10e6,
+ )
+ vega.mint(
+ PARTY_B.name,
+ asset=tdai_id,
+ amount=10e6,
+ )
+
+ submit_liquidity(vega, MM_WALLET.name, continuous_market, 100, 100)
+ forward_time(vega)
+
+
+@pytest.mark.usefixtures("page", "auth", "risk_accepted")
+def test_can_traverse_up_and_down_through_tiers(continuous_market, vega: VegaService, page: Page):
+ setup_market_and_referral_scheme(vega, continuous_market, page)
+ change_keys(page, vega, PARTY_B.name)
+ submit_order(vega, PARTY_B.name, continuous_market, "SIDE_BUY", 1, 115)
+ forward_time(vega, True)
+ check_tile_values(page, generate_referral_expected_value_dic(
+ "110", "1", "1%", "1", "1"))
+
+ change_keys(page, vega, PARTY_A.name)
+ check_tile_values(page, generate_referrer_expected_value_dic(
+ "1%", "1", "1%", "0", "1", "0"))
+
+ change_keys(page, vega, PARTY_B.name)
+ submit_order(vega, PARTY_B.name, continuous_market, "SIDE_BUY", 2, 115)
+ forward_time(vega, True)
+ check_tile_values(page, generate_referral_expected_value_dic(
+ "221", "2", "2%", "2", "1"))
+
+ change_keys(page, vega, PARTY_A.name)
+ check_tile_values(page, generate_referrer_expected_value_dic(
+ "2%", "1", "2%", "0", "1", "0"))
+
+ change_keys(page, vega, PARTY_B.name)
+ submit_order(vega, PARTY_B.name, continuous_market, "SIDE_BUY", 3, 115)
+ forward_time(vega, True)
+ check_tile_values(page, generate_referral_expected_value_dic(
+ "331", "3", "3%", "3", "0"))
+
+ change_keys(page, vega, PARTY_A.name)
+ check_tile_values(page, generate_referrer_expected_value_dic(
+ "3%", "1", "3%", "0", "1", "1"))
+
+ change_keys(page, vega, PARTY_B.name)
+ submit_order(vega, PARTY_B.name, continuous_market, "SIDE_BUY", 1, 115)
+ forward_time(vega, True)
+ check_tile_values(page, generate_referral_expected_value_dic(
+ "110", "1", "1%", "4", "0"))
+
+ change_keys(page, vega, PARTY_A.name)
+ check_tile_values(page, generate_referrer_expected_value_dic(
+ "1%", "1", "1%", "0", "1", "1"))
+
+
+@pytest.mark.usefixtures("page", "auth", "risk_accepted")
+def test_does_not_move_up_tiers_when_not_enough_epochs(continuous_market, vega: VegaService, page: Page):
+ setup_market_and_referral_scheme(vega, continuous_market, page)
+ change_keys(page, vega, PARTY_B.name)
+ submit_order(vega, PARTY_B.name, continuous_market, "SIDE_BUY", 2, 115)
+ forward_time(vega, True)
+ check_tile_values(page, generate_referral_expected_value_dic(
+ "221", "1", "1%", "1", "1"))
+
+ change_keys(page, vega, PARTY_A.name)
+ check_tile_values(page, generate_referrer_expected_value_dic(
+ "2%", "1", "2%", "0", "1", "0"))
diff --git a/apps/trading/e2e/wallet_config.py b/apps/trading/e2e/wallet_config.py
index f85dd8374..c078666bf 100644
--- a/apps/trading/e2e/wallet_config.py
+++ b/apps/trading/e2e/wallet_config.py
@@ -7,6 +7,9 @@ WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
MM_WALLET = WalletConfig("market_maker", "pin")
MM_WALLET2 = WalletConfig("market_maker_2", "pin2")
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
-GOVERNANCE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
+GOVERNANCE_WALLET = WalletConfig(
+ "FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
+PARTY_A = WalletConfig("party_a", "party_a")
+PARTY_B = WalletConfig("party_b", "party_b")
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET, GOVERNANCE_WALLET]