diff --git a/Makefile b/Makefile index 59364a332..6a15e05c7 100644 --- a/Makefile +++ b/Makefile @@ -111,7 +111,11 @@ flake8: .PHONY: test test: - @env PYTHONPATH=. pytest -m "not integration" tests/ + @env PYTHONPATH=. pytest -m "not integration and not api" tests/ + +.PHONY: test_api +test_api: + @env PYTHONPATH=. pytest -m api tests/ .PHONY: test_integration test_integration: diff --git a/pytest.ini b/pytest.ini index 343b5b50d..679debd82 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,6 +1,7 @@ [pytest] markers = - integration: mark a test as requiring a full vega sim infrastructure with running backend + integration: mark a test as requiring a full vega sim infrastructure with running backend\ + api: mark a test as checking vega-market-sim api coverage log_file_format=%(asctime)s.%(msecs)03d %(threadName)s %(processName)s (%(filename)s:%(funcName)s:%(lineno)s):%(message)s log_file_date_format=%Y-%m-%d %H:%M:%S diff --git a/tests/integration/test_trading.py b/tests/integration/test_trading.py index 537d8b66b..88c27f992 100644 --- a/tests/integration/test_trading.py +++ b/tests/integration/test_trading.py @@ -1714,3 +1714,58 @@ def test_volume_discount_program(vega_service_with_market: VegaServiceNull): assert discounted_trades[0].buyer_fee.maker_fee_volume_discount != 0 assert discounted_trades[0].buyer_fee.liquidity_fee_volume_discount != 0 assert discounted_trades[0].buyer_fee.infrastructure_fee_volume_discount != 0 + + +@pytest.mark.integration +def test_teams(vega_service_with_market: VegaServiceNull): + vega = vega_service_with_market + + # Initialise parties + create_and_faucet_wallet(vega=vega, wallet=PARTY_A) + vega.wait_for_total_catchup() + create_and_faucet_wallet(vega=vega, wallet=PARTY_B) + vega.wait_for_total_catchup() + create_and_faucet_wallet(vega=vega, wallet=PARTY_C) + vega.wait_for_total_catchup() + + # Create referral sets, teams from sets, then get team ids + vega.create_referral_set( + key_name=PARTY_A.name, + name="name_a", + team_url="team_url_a", + avatar_url="avatar_url_a", + closed=False, + ) + vega.create_referral_set( + key_name=PARTY_B.name, + name="name_b", + team_url="team_url_b", + avatar_url="avatar_url_b", + closed=False, + ) + vega.wait_fn((1)) + vega.wait_for_total_catchup() + team_a_id = list(vega.list_teams(key_name=PARTY_A.name).keys())[0] + team_b_id = list(vega.list_teams(key_name=PARTY_B.name).keys())[0] + + # Apply code and check the party has joined team + vega.apply_referral_code(key_name=PARTY_C.name, id=team_a_id) + next_epoch(vega) + assert len(vega.list_team_referees(team_id=team_a_id)) > 0 + assert len(vega.list_team_referees(team_id=team_b_id)) == 0 + + # Apply code and check the party has moved team + vega.apply_referral_code(key_name=PARTY_C.name, id=team_b_id) + next_epoch(vega) + assert len(vega.list_team_referees(team_id=team_a_id)) == 0 + assert len(vega.list_team_referees(team_id=team_b_id)) > 0 + + # Check the history is consistent + team_referee_history = [ + team_referee_history.team_id + for team_referee_history in vega.list_team_referee_history( + key_name=PARTY_C.name + ) + ] + assert team_a_id in team_referee_history + assert team_b_id in team_referee_history diff --git a/tests/vega_sim/api/test_api_coverage.py b/tests/vega_sim/api/test_api_coverage.py new file mode 100644 index 000000000..dce3e1849 --- /dev/null +++ b/tests/vega_sim/api/test_api_coverage.py @@ -0,0 +1,76 @@ +"""Module contains tests for testing coverage of vega APIs. +""" + +import pytest +import re + +import vega_sim.proto.data_node.api.v2 as data_node_protos_v2 +import vega_sim.proto.vega as vega_protos +import vega_sim.api.data as data +import vega_sim.api.data_raw as data_raw + + +def camel_to_snake(camel_case): + # Use regular expression to split words at capital letters + words = re.findall("[A-Z][a-z]*", camel_case) + # Join the words with underscores and convert to lowercase + snake_case = "_".join(word.lower() for word in words) + return snake_case + + +@pytest.mark.api +@pytest.mark.parametrize( + "item_name", + [ + item_name + for item_name in dir(vega_protos.vega) + if hasattr(getattr(vega_protos.vega, item_name), "DESCRIPTOR") + and hasattr(getattr(vega_protos.vega, item_name), "SerializeToString") + ], +) +def test_vega_protos(item_name): + assert hasattr(data, item_name) + + +@pytest.mark.api +@pytest.mark.parametrize( + "item_name", + [ + item_name + for item_name in dir(vega_protos.events.v1.events) + if hasattr(getattr(vega_protos.events.v1.events, item_name), "DESCRIPTOR") + and hasattr( + getattr(vega_protos.events.v1.events, item_name), "SerializeToString" + ) + ], +) +def test_events_protos(item_name): + assert hasattr(data, item_name) + + +@pytest.mark.api +@pytest.mark.parametrize( + "item_name", + [ + item_name + for item_name in dir(vega_protos.assets) + if hasattr(getattr(vega_protos.assets, item_name), "DESCRIPTOR") + and hasattr(getattr(vega_protos.assets, item_name), "SerializeToString") + ], +) +def test_assets_protos(item_name): + assert hasattr(data, item_name) + + +@pytest.mark.api +@pytest.mark.parametrize( + "item_name", + [ + method.name + for method in data_node_protos_v2.trading_data.DESCRIPTOR.services_by_name[ + "TradingDataService" + ].methods + ], +) +def test_trading_data(item_name): + assert hasattr(data_raw, camel_to_snake(item_name)) diff --git a/tests/vega_sim/api/test_data.py b/tests/vega_sim/api/test_data.py index ea199a42e..e495f868a 100644 --- a/tests/vega_sim/api/test_data.py +++ b/tests/vega_sim/api/test_data.py @@ -24,6 +24,13 @@ LiquidationPrice, ReferralSet, ReferralSetReferee, + ReferralSetStats, + PartyAmount, + ReferrerRewardsGenerated, + FeeStats, + Team, + TeamReferee, + TeamRefereeHistory, get_asset_decimals, find_asset_id, get_trades, @@ -37,6 +44,11 @@ estimate_position, list_referral_sets, list_referral_set_referees, + get_referral_set_stats, + get_referral_fee_stats, + list_teams, + list_team_referees, + list_team_referee_history, ) from vega_sim.grpc.client import ( VegaTradingDataClientV2, @@ -980,3 +992,262 @@ def ListReferralSetReferees(self, request, context): ) } } + + +def test_get_referral_set_stats(trading_data_v2_servicer_and_port): + def GetReferralSetStats(self, request, context): + return data_node_protos_v2.trading_data.GetReferralSetStatsResponse( + stats=data_node_protos_v2.trading_data.ReferralSetStatsConnection( + page_info=data_node_protos_v2.trading_data.PageInfo( + has_next_page=False, + has_previous_page=False, + start_cursor="", + end_cursor="", + ), + edges=[ + data_node_protos_v2.trading_data.ReferralSetStatsEdge( + cursor="cursor", + node=data_node_protos_v2.trading_data.ReferralSetStats( + at_epoch=request.at_epoch, + referral_set_running_notional_taker_volume="1000", + party_id=request.referee, + discount_factor="0.1", + reward_factor="0.1", + epoch_notional_taker_volume="1000", + ), + ), + ], + ) + ) + + server, port, mock_servicer = trading_data_v2_servicer_and_port + mock_servicer.GetReferralSetStats = GetReferralSetStats + + add_TradingDataServiceServicer_v2_to_server(mock_servicer(), server) + + data_client = VegaTradingDataClientV2(f"localhost:{port}") + assert get_referral_set_stats(data_client=data_client, at_epoch=1) == [ + ReferralSetStats( + at_epoch=1, + referral_set_running_notional_taker_volume=1000.0, + party_id="", + discount_factor=0.1, + reward_factor=0.1, + epoch_notional_taker_volume=1000.0, + ) + ] + assert get_referral_set_stats(data_client=data_client, referee="referee") == [ + ReferralSetStats( + at_epoch=0, + referral_set_running_notional_taker_volume=1000.0, + party_id="referee", + discount_factor=0.1, + reward_factor=0.1, + epoch_notional_taker_volume=1000.0, + ) + ] + + +def test_get_referral_fee_stats(trading_data_v2_servicer_and_port): + def GetReferralFeeStats(self, request, context): + return data_node_protos_v2.trading_data.GetReferralFeeStatsResponse( + fee_stats=vega_protos.events.v1.events.FeeStats( + market=request.market_id, + asset=request.asset_id, + epoch_seq=1, + total_rewards_paid=[ + vega_protos.events.v1.events.PartyAmount( + party="referrer1", amount="1000" + ) + ], + referrer_rewards_generated=[ + vega_protos.events.v1.events.ReferrerRewardsGenerated( + referrer="referrer1", + generated_reward=[ + vega_protos.events.v1.events.PartyAmount( + party="referee1", amount="1000" + ) + ], + ) + ], + referees_discount_applied=[ + vega_protos.events.v1.events.PartyAmount( + party="referrer1", amount="1000" + ) + ], + volume_discount_applied=[ + vega_protos.events.v1.events.PartyAmount( + party="referrer1", amount="1000" + ) + ], + ) + ) + + server, port, mock_servicer = trading_data_v2_servicer_and_port + mock_servicer.GetReferralFeeStats = GetReferralFeeStats + + add_TradingDataServiceServicer_v2_to_server(mock_servicer(), server) + + data_client = VegaTradingDataClientV2(f"localhost:{port}") + assert get_referral_fee_stats( + data_client=data_client, + market_id="market_id", + asset_decimals={"": 1}, + ) == FeeStats( + market="market_id", + asset="", + epoch_seq=1, + total_rewards_paid=[PartyAmount(party="referrer1", amount=100.0)], + referrer_rewards_generated=[ + ReferrerRewardsGenerated( + referrer="referrer1", + generated_reward=[PartyAmount(party="referee1", amount=100.0)], + ) + ], + referees_discount_applied=[PartyAmount(party="referrer1", amount=100.0)], + volume_discount_applied=[PartyAmount(party="referrer1", amount=100.0)], + ) + assert get_referral_fee_stats( + data_client=data_client, + asset_id="asset", + asset_decimals={"asset": 1}, + ) == FeeStats( + market="", + asset="asset", + epoch_seq=1, + total_rewards_paid=[PartyAmount(party="referrer1", amount=100.0)], + referrer_rewards_generated=[ + ReferrerRewardsGenerated( + referrer="referrer1", + generated_reward=[PartyAmount(party="referee1", amount=100.0)], + ) + ], + referees_discount_applied=[PartyAmount(party="referrer1", amount=100.0)], + volume_discount_applied=[PartyAmount(party="referrer1", amount=100.0)], + ) + + +def test_list_teams(trading_data_v2_servicer_and_port): + def ListTeams(self, request, context): + return data_node_protos_v2.trading_data.ListTeamsResponse( + teams=data_node_protos_v2.trading_data.TeamConnection( + page_info=data_node_protos_v2.trading_data.PageInfo( + has_next_page=False, + has_previous_page=False, + start_cursor="", + end_cursor="", + ), + edges=[ + data_node_protos_v2.trading_data.TeamEdge( + cursor="cursor", + node=data_node_protos_v2.trading_data.Team( + team_id=request.team_id, + referrer="referrer", + name="name", + team_url="team_url", + avatar_url="avatar_url", + created_at=123456789, + closed=False, + created_at_epoch=1, + ), + ), + ], + ) + ) + + server, port, mock_servicer = trading_data_v2_servicer_and_port + mock_servicer.ListTeams = ListTeams + + add_TradingDataServiceServicer_v2_to_server(mock_servicer(), server) + + data_client = VegaTradingDataClientV2(f"localhost:{port}") + assert list_teams(data_client=data_client, team_id="id") == { + "id": Team( + team_id="id", + referrer="referrer", + name="name", + team_url="team_url", + avatar_url="avatar_url", + created_at=123456789, + closed=False, + created_at_epoch=1, + ) + } + + +def test_list_team_referees(trading_data_v2_servicer_and_port): + def ListTeamReferees(self, request, context): + return data_node_protos_v2.trading_data.ListTeamRefereesResponse( + team_referees=data_node_protos_v2.trading_data.TeamRefereeConnection( + page_info=data_node_protos_v2.trading_data.PageInfo( + has_next_page=False, + has_previous_page=False, + start_cursor="", + end_cursor="", + ), + edges=[ + data_node_protos_v2.trading_data.TeamRefereeEdge( + cursor="cursor", + node=data_node_protos_v2.trading_data.TeamReferee( + team_id=request.team_id, + referee="referee", + joined_at=123456789, + joined_at_epoch=1, + ), + ), + ], + ) + ) + + server, port, mock_servicer = trading_data_v2_servicer_and_port + mock_servicer.ListTeamReferees = ListTeamReferees + + add_TradingDataServiceServicer_v2_to_server(mock_servicer(), server) + + data_client = VegaTradingDataClientV2(f"localhost:{port}") + assert list_team_referees(data_client=data_client, team_id="id") == [ + TeamReferee( + team_id="id", + referee="referee", + joined_at=123456789, + joined_at_epoch=1, + ) + ] + + +def test_list_team_referee_history(trading_data_v2_servicer_and_port): + def ListTeamRefereeHistory(self, request, context): + return data_node_protos_v2.trading_data.ListTeamRefereeHistoryResponse( + team_referee_history=data_node_protos_v2.trading_data.TeamRefereeHistoryConnection( + page_info=data_node_protos_v2.trading_data.PageInfo( + has_next_page=False, + has_previous_page=False, + start_cursor="", + end_cursor="", + ), + edges=[ + data_node_protos_v2.trading_data.TeamRefereeHistoryEdge( + cursor="cursor", + node=data_node_protos_v2.trading_data.TeamRefereeHistory( + team_id="id", + joined_at=123456789, + joined_at_epoch=1, + ), + ), + ], + ) + ) + + server, port, mock_servicer = trading_data_v2_servicer_and_port + mock_servicer.ListTeamRefereeHistory = ListTeamRefereeHistory + + add_TradingDataServiceServicer_v2_to_server(mock_servicer(), server) + + data_client = VegaTradingDataClientV2(f"localhost:{port}") + assert list_team_referee_history(data_client=data_client, referee="id") == [ + TeamRefereeHistory( + team_id="id", + joined_at=123456789, + joined_at_epoch=1, + ) + ] diff --git a/vega_sim/api/data.py b/vega_sim/api/data.py index fb6de5e7b..10845a7b5 100644 --- a/vega_sim/api/data.py +++ b/vega_sim/api/data.py @@ -278,6 +278,39 @@ class ReferralSetReferee: at_epoch: int +@dataclass(frozen=True) +class ReferralSetStats: + at_epoch: int + referral_set_running_notional_taker_volume: float + party_id: str + discount_factor: float + reward_factor: float + epoch_notional_taker_volume: float + + +@dataclass(frozen=True) +class PartyAmount: + party: str + amount: float + + +@dataclass(frozen=True) +class ReferrerRewardsGenerated: + referrer: str + generated_reward: List[PartyAmount] + + +@dataclass(frozen=True) +class FeeStats: + market: str + asset: str + epoch_seq: int + total_rewards_paid: List[PartyAmount] + referrer_rewards_generated: List[ReferrerRewardsGenerated] + referees_discount_applied: List[PartyAmount] + volume_discount_applied: List[PartyAmount] + + @dataclass(frozen=True) class VolumeDiscountStats: at_epoch: int @@ -327,6 +360,33 @@ class VolumeDiscountProgram: ended_at: int +@dataclass(frozen=True) +class Team: + team_id: str + referrer: str + name: str + team_url: str + avatar_url: str + created_at: int + closed: bool + created_at_epoch: int + + +@dataclass(frozen=True) +class TeamReferee: + team_id: str + referee: str + joined_at: int + joined_at_epoch: int + + +@dataclass(frozen=True) +class TeamRefereeHistory: + team_id: str + joined_at: int + joined_at_epoch: int + + def _ledger_entry_from_proto( ledger_entry, asset_decimals: int, @@ -846,6 +906,82 @@ def _referral_program_from_proto(referral_program) -> ReferralProgram: ) +def _referral_set_stats_from_proto( + referral_set_stats: data_node_protos_v2.trading_data.ReferralSetStats, +) -> ReferralSetStats: + return ReferralSetStats( + at_epoch=referral_set_stats.at_epoch, + referral_set_running_notional_taker_volume=int( + referral_set_stats.referral_set_running_notional_taker_volume + ), + party_id=referral_set_stats.party_id, + discount_factor=float(referral_set_stats.discount_factor), + reward_factor=float(referral_set_stats.reward_factor), + epoch_notional_taker_volume=int(referral_set_stats.epoch_notional_taker_volume), + ) + + +def _party_amount_from_proto( + party_amount: vega_protos.events.v1.events.PartyAmount, + decimal_spec: DecimalSpec, +) -> PartyAmount: + return PartyAmount( + party=party_amount.party, + amount=num_from_padded_int(party_amount.amount, decimal_spec.asset_decimals), + ) + + +def _referrer_rewards_generated_from_proto( + referrer_rewards_generated: vega_protos.events.v1.events.ReferrerRewardsGenerated, + decimal_spec: DecimalSpec, +) -> ReferrerRewardsGenerated: + return ReferrerRewardsGenerated( + referrer=referrer_rewards_generated.referrer, + generated_reward=[ + _party_amount_from_proto( + party_amount=generated_reward, + decimal_spec=decimal_spec, + ) + for generated_reward in referrer_rewards_generated.generated_reward + ], + ) + + +def _fee_stats_from_proto( + fee_stats: vega_protos.events.v1.events.FeeStats, decimal_spec: DecimalSpec +): + return FeeStats( + market=fee_stats.market, + asset=fee_stats.asset, + epoch_seq=fee_stats.epoch_seq, + total_rewards_paid=[ + _party_amount_from_proto( + party_amount=party_amount, decimal_spec=decimal_spec + ) + for party_amount in fee_stats.total_rewards_paid + ], + referrer_rewards_generated=[ + _referrer_rewards_generated_from_proto( + referrer_rewards_generated=referrer_rewards_generated, + decimal_spec=decimal_spec, + ) + for referrer_rewards_generated in fee_stats.referrer_rewards_generated + ], + referees_discount_applied=[ + _party_amount_from_proto( + party_amount=party_amount, decimal_spec=decimal_spec + ) + for party_amount in fee_stats.referees_discount_applied + ], + volume_discount_applied=[ + _party_amount_from_proto( + party_amount=party_amount, decimal_spec=decimal_spec + ) + for party_amount in fee_stats.volume_discount_applied + ], + ) + + def _volume_benefit_tier_from_proto(volume_benefit_tier) -> VolumeBenefitTier: return VolumeBenefitTier( minimum_running_notional_taker_volume=float( @@ -880,6 +1016,40 @@ def _volume_discount_stats_from_proto(volume_discount_stats) -> VolumeDiscountSt ) +def _team_from_proto(team: data_node_protos_v2.trading_data.Team) -> Team: + return Team( + team_id=team.team_id, + referrer=team.referrer, + name=team.name, + team_url=team.team_url, + avatar_url=team.avatar_url, + created_at=team.created_at, + closed=team.closed, + created_at_epoch=team.created_at_epoch, + ) + + +def _team_referee_from_proto( + team_referee: data_node_protos_v2.trading_data.TeamReferee, +) -> TeamReferee: + return TeamReferee( + team_id=team_referee.team_id, + referee=team_referee.referee, + joined_at=team_referee.joined_at, + joined_at_epoch=team_referee.joined_at_epoch, + ) + + +def _team_referee_history_from_proto( + team_referee_history: data_node_protos_v2.trading_data.TeamRefereeHistory, +) -> TeamRefereeHistory: + return TeamRefereeHistory( + team_id=team_referee_history.team_id, + joined_at=team_referee_history.joined_at, + joined_at_epoch=team_referee_history.joined_at_epoch, + ) + + def list_accounts( data_client: vac.VegaTradingDataClientV2, pub_key: Optional[str] = None, @@ -1920,6 +2090,39 @@ def list_referral_set_referees( return referral_set_referees +def get_referral_set_stats( + data_client: vac.trading_data_grpc_v2, + at_epoch: Optional[int] = None, + referee: Optional[str] = None, +) -> Dict[str, ReferralSetStats]: + response = data_raw.get_referral_set_stats( + data_client=data_client, at_epoch=at_epoch, referee=referee + ) + return [ + _referral_set_stats_from_proto(referral_set_stats=referral_set_stats) + for referral_set_stats in response + ] + + +def get_referral_fee_stats( + data_client: vac.trading_data_grpc_v2, + market_id: Optional[str] = None, + asset_id: Optional[str] = None, + epoch_seq: Optional[int] = None, + asset_decimals: Optional[Dict[str, int]] = {}, +) -> List[FeeStats]: + response = data_raw.get_referral_fee_stats( + data_client=data_client, + market_id=market_id, + asset_id=asset_id, + epoch_seq=epoch_seq, + ) + return _fee_stats_from_proto( + fee_stats=response, + decimal_spec=DecimalSpec(asset_decimals=asset_decimals[response.asset]), + ) + + def get_current_referral_program( data_client: vac.trading_data_grpc_v2, ) -> ReferralProgram: @@ -2013,3 +2216,37 @@ def dispatch_strategy( if rank_table is not None: dispatch_strategy.rank_table.extend(rank_table) return dispatch_strategy + + +def list_teams( + data_client: vac.trading_data_grpc_v2, + team_id: Optional[str] = None, + party_id: Optional[str] = None, +) -> Dict[str, Team]: + response = data_raw.list_teams( + data_client=data_client, team_id=team_id, party_id=party_id + ) + return {team.team_id: _team_from_proto(team=team) for team in response} + + +def list_team_referees( + data_client: vac.trading_data_grpc_v2, + team_id: Optional[str] = None, +) -> List[TeamReferee]: + response = data_raw.list_team_referees(data_client=data_client, team_id=team_id) + return [ + _team_referee_from_proto(team_referee=team_referee) for team_referee in response + ] + + +def list_team_referee_history( + data_client: vac.trading_data_grpc_v2, + referee: Optional[str] = None, +) -> List[TeamRefereeHistory]: + response = data_raw.list_team_referee_history( + data_client=data_client, referee=referee + ) + return [ + _team_referee_history_from_proto(team_referee_history=team_referee_history) + for team_referee_history in response + ] diff --git a/vega_sim/api/data_raw.py b/vega_sim/api/data_raw.py index 4ceb4a265..e1777fd5b 100644 --- a/vega_sim/api/data_raw.py +++ b/vega_sim/api/data_raw.py @@ -735,6 +735,43 @@ def get_current_referral_program(data_client: vac.trading_data_grpc_v2): ).current_referral_program +@_retry(3) +def get_referral_set_stats( + data_client: vac.trading_data_grpc_v2, + at_epoch: Optional[int] = None, + referee: Optional[str] = None, +): + base_request = data_node_protos_v2.trading_data.GetReferralSetStatsRequest() + if at_epoch is not None: + setattr(base_request, "at_epoch", at_epoch) + if referee is not None: + setattr(base_request, "referee", referee) + return unroll_v2_pagination( + base_request=base_request, + request_func=lambda x: data_client.GetReferralSetStats(x).stats, + extraction_func=lambda res: [i.node for i in res.edges], + ) + + +@_retry(3) +def get_referral_fee_stats( + data_client: vac.trading_data_grpc_v2, + market_id: Optional[str] = None, + asset_id: Optional[str] = None, + epoch_seq: Optional[int] = None, +): + base_request = data_node_protos_v2.trading_data.GetReferralFeeStatsRequest() + if market_id is None and asset_id is None: + raise ValueError("Neither 'market_id' or 'asset_id' set.") + if market_id is not None: + setattr(base_request, "market_id", market_id) + if asset_id is not None: + setattr(base_request, "asset_id", asset_id) + if epoch_seq is not None: + setattr(base_request, "epoch_seq", epoch_seq) + return data_client.GetReferralFeeStats(base_request).fee_stats + + @_retry(3) def get_current_volume_discount_program( data_client: vac.trading_data_grpc_v2.TradingDataServiceStub, @@ -760,3 +797,53 @@ def get_volume_discount_stats( request_func=lambda x: data_client.GetVolumeDiscountStats(x).stats, extraction_func=lambda res: [i.node for i in res.edges], ) + + +@_retry(3) +def list_teams( + data_client: vac.trading_data_grpc_v2, + team_id: Optional[str] = None, + party_id: Optional[str] = None, +): + base_request = data_node_protos_v2.trading_data.ListTeamsRequest() + if team_id is not None: + setattr(base_request, "team_id", team_id) + if party_id is not None: + setattr(base_request, "party_id", party_id) + return unroll_v2_pagination( + base_request=base_request, + request_func=lambda x: data_client.ListTeams(x).teams, + extraction_func=lambda res: [i.node for i in res.edges], + ) + + +@_retry(3) +def list_team_referees( + data_client: vac.trading_data_grpc_v2, + team_id: Optional[str] = None, +): + base_request = data_node_protos_v2.trading_data.ListTeamRefereesRequest() + if team_id is not None: + setattr(base_request, "team_id", team_id) + return unroll_v2_pagination( + base_request=base_request, + request_func=lambda x: data_client.ListTeamReferees(x).team_referees, + extraction_func=lambda res: [i.node for i in res.edges], + ) + + +@_retry(3) +def list_team_referee_history( + data_client: vac.trading_data_grpc_v2, + referee: Optional[str] = None, +): + base_request = data_node_protos_v2.trading_data.ListTeamRefereeHistoryRequest() + if referee is not None: + setattr(base_request, "referee", referee) + return unroll_v2_pagination( + base_request=base_request, + request_func=lambda x: data_client.ListTeamRefereeHistory( + x + ).team_referee_history, + extraction_func=lambda res: [i.node for i in res.edges], + ) diff --git a/vega_sim/api/trading.py b/vega_sim/api/trading.py index 7983abe05..cbdf82faa 100644 --- a/vega_sim/api/trading.py +++ b/vega_sim/api/trading.py @@ -669,16 +669,30 @@ def transfer( def create_referral_set( - wallet: Wallet, key_name: str, wallet_name: Optional[str] = None + wallet: Wallet, + key_name: str, + name: Optional[str] = None, + team_url: Optional[str] = None, + avatar_url: Optional[str] = None, + closed: Optional[bool] = None, + wallet_name: Optional[str] = None, ): - is_team = False + if any(arg is not None for arg in [name, team_url, avatar_url, closed]): + is_team = True + else: + is_team = False command = vega_protos.commands.v1.commands.CreateReferralSet( is_team=is_team, ) if is_team: + if (name is None) or (closed is None): + raise ValueError("If one team arg passed, all team args must be passed.") command.team.CopyFrom( vega_protos.commands.v1.commands.CreateReferralSet.Team( - name="name", team_url="name", avatar_url="name", closed=False + name=name, + team_url=team_url if team_url is not None else "team_url", + avatar_url=avatar_url if avatar_url is not None else "avatar_url", + closed=closed, ) ) wallet.submit_transaction( @@ -691,16 +705,30 @@ def create_referral_set( def update_referral_set( - wallet: Wallet, key_name: str, wallet_name: Optional[str] = None + wallet: Wallet, + key_name: str, + name: Optional[str] = None, + team_url: Optional[str] = None, + avatar_url: Optional[str] = None, + closed: Optional[bool] = None, + wallet_name: Optional[str] = None, ): - is_team = True + if any(arg is not None for arg in [name, team_url, avatar_url, closed]): + is_team = True + else: + is_team = False command = vega_protos.commands.v1.commands.UpdateReferralSet( is_team=is_team, ) if is_team: + if (name is None) or (closed is None): + raise ValueError("If one team arg passed, all team args must be passed.") command.team.CopyFrom( - vega_protos.commands.v1.commands.UpdateReferralSet.Team( - name="name", team_url="name", avatar_url="name", closed=False + vega_protos.commands.v1.commands.CreateReferralSet.Team( + name=name, + team_url=team_url if team_url is not None else "team_url", + avatar_url=avatar_url if avatar_url is not None else "avatar_url", + closed=closed, ) ) wallet.submit_transaction( diff --git a/vega_sim/scenario/common/agents.py b/vega_sim/scenario/common/agents.py index 3a566b2a6..56bf884be 100644 --- a/vega_sim/scenario/common/agents.py +++ b/vega_sim/scenario/common/agents.py @@ -3457,6 +3457,10 @@ def __init__( self, agent: StateAgentWithWallet, is_referrer: bool = False, + team_name: Optional[str] = None, + team_url: Optional[str] = None, + avatar_url: Optional[str] = None, + closed: bool = False, referrer_key_name: Optional[str] = None, referrer_wallet_name: Optional[str] = None, ): @@ -3468,6 +3472,10 @@ def __init__( ) self.is_referrer = is_referrer + self.team_name = team_name + self.team_url = team_url + self.avatar_url = avatar_url + self.closed = closed self.referrer_key_name = referrer_key_name self.referrer_wallet_name = referrer_wallet_name self.applied_code = False @@ -3482,7 +3490,12 @@ def initialise( self._agent.initialise(vega=vega, create_key=create_key, mint_key=mint_key) if self.is_referrer: self._agent.vega.create_referral_set( - key_name=self._agent.key_name, wallet_name=self._agent.wallet_name + key_name=self._agent.key_name, + wallet_name=self._agent.wallet_name, + name=self.team_name, + team_url=self.team_url, + avatar_url=self.avatar_url, + closed=self.closed, ) def step(self, vega_state: VegaState): diff --git a/vega_sim/scenario/fuzzed_markets/scenario.py b/vega_sim/scenario/fuzzed_markets/scenario.py index c3940f7c2..0605b974b 100644 --- a/vega_sim/scenario/fuzzed_markets/scenario.py +++ b/vega_sim/scenario/fuzzed_markets/scenario.py @@ -312,6 +312,10 @@ def configure_agents( tag=str(i_agent), ), is_referrer=True, + team_name=f"TEAM_{i_agent}", + team_url=f"URL_{i_agent}", + avatar_url=f"AVATAR_{i_agent}", + closed=False, ) for i_agent in range(num_referrers) ] diff --git a/vega_sim/service.py b/vega_sim/service.py index ab7ab3af3..290989945 100644 --- a/vega_sim/service.py +++ b/vega_sim/service.py @@ -2729,14 +2729,42 @@ def update_referral_program( self.wait_for_thread_catchup() return proposal_id - def create_referral_set(self, key_name: str, wallet_name: Optional[str] = None): + def create_referral_set( + self, + key_name: str, + name: Optional[str] = None, + team_url: Optional[str] = None, + avatar_url: Optional[str] = None, + closed: Optional[bool] = None, + wallet_name: Optional[str] = None, + ): trading.create_referral_set( - wallet=self.wallet, key_name=key_name, wallet_name=wallet_name + wallet=self.wallet, + key_name=key_name, + wallet_name=wallet_name, + name=name, + team_url=team_url, + avatar_url=avatar_url, + closed=closed, ) - def update_referral_set(self, key_name: str, wallet_name: Optional[str] = None): + def update_referral_set( + self, + key_name: str, + name: Optional[str] = None, + team_url: Optional[str] = None, + avatar_url: Optional[str] = None, + closed: Optional[bool] = None, + wallet_name: Optional[str] = None, + ): trading.update_referral_set( - wallet=self.wallet, key_name=key_name, wallet_name=wallet_name + wallet=self.wallet, + key_name=key_name, + wallet_name=wallet_name, + name=name, + team_url=team_url, + avatar_url=avatar_url, + closed=closed, ) def apply_referral_code( @@ -2779,6 +2807,32 @@ def get_current_referral_program( data_client=self.trading_data_client_v2 ) + def get_referral_set_stats( + self, + at_epoch: Optional[int] = None, + key_name: Optional[str] = None, + wallet_name: Optional[str] = None, + ) -> List[data.ReferralSetStats]: + return data.get_referral_set_stats( + data_client=self.trading_data_client_v2, + at_epoch=at_epoch, + referee=self.wallet.public_key(name=key_name, wallet_name=wallet_name), + ) + + def get_referral_fee_stats( + self, + market_id: Optional[str] = None, + asset_id: Optional[str] = None, + epoch_seq: Optional[int] = None, + ) -> List[data.FeeStats]: + return data.get_referral_fee_stats( + data_client=self.trading_data_client_v2, + market_id=market_id, + asset_id=asset_id, + epoch_seq=epoch_seq, + asset_decimals=self.asset_decimals, + ) + def update_volume_discount_program( self, proposal_key: str, @@ -2853,3 +2907,33 @@ def get_volume_discount_stats( at_epoch=at_epoch, party_id=self.wallet.public_key(name=key_name, wallet_name=wallet_name), ) + + def list_teams( + self, + key_name: Optional[str], + wallet_name: Optional[str] = None, + team_id: Optional[str] = None, + ) -> List[data.Team]: + return data.list_teams( + data_client=self.trading_data_client_v2, + team_id=team_id, + party_id=self.wallet.public_key(name=key_name, wallet_name=wallet_name), + ) + + def list_team_referees( + self, + team_id: Optional[str] = None, + ) -> List[data.TeamReferee]: + return data.list_team_referees( + data_client=self.trading_data_client_v2, team_id=team_id + ) + + def list_team_referee_history( + self, + key_name: str, + wallet_name: Optional[str] = None, + ) -> List[data.TeamRefereeHistory]: + return data.list_team_referee_history( + data_client=self.trading_data_client_v2, + referee=self.wallet.public_key(name=key_name, wallet_name=wallet_name), + ) diff --git a/vega_sim/vegahome/genesis.json b/vega_sim/vegahome/genesis.json index 82a5f61c2..89d01239c 100644 --- a/vega_sim/vegahome/genesis.json +++ b/vega_sim/vegahome/genesis.json @@ -188,6 +188,7 @@ "spam.protection.minMultisigUpdates": "100000000000000000000", "spam.protection.proposal.min.tokens": "2000000000000000000000", "spam.protection.voting.min.tokens": "1000000000000000000", + "spam.protection.applyReferral.min.funds": "0", "transfer.fee.factor": "0.001", "transfer.minTransferQuantumMultiple": "100", "validator.performance.scaling.factor": "0",