Merge pull request #5492 from vegaprotocol/test/referrals2

test: add referrals tests
This commit is contained in:
dalebennett1992 2023-12-12 10:33:57 +00:00 committed by GitHub
commit 67be224138
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 280 additions and 27 deletions

View File

@ -212,6 +212,7 @@ export const Statistics = ({
).toString(), ).toString(),
} }
)} )}
testId="base-commission-rate"
overrideWithNoProgram={!details} overrideWithNoProgram={!details}
> >
{baseCommissionValue * 100}% {baseCommissionValue * 100}%
@ -221,6 +222,7 @@ export const Statistics = ({
const stakingMultiplierTile = ( const stakingMultiplierTile = (
<StatTile <StatTile
title={t('Staking multiplier')} title={t('Staking multiplier')}
testId="staking-multiplier"
description={ description={
<span <span
className={classNames({ className={classNames({
@ -254,6 +256,7 @@ export const Statistics = ({
? `(${baseCommissionFormatted}% ⨉ ${multiplier} = ${finalCommissionFormatted}%)` ? `(${baseCommissionFormatted}% ⨉ ${multiplier} = ${finalCommissionFormatted}%)`
: undefined : undefined
} }
testId="final-commission-rate"
overrideWithNoProgram={!details} overrideWithNoProgram={!details}
> >
{finalCommissionFormatted}% {finalCommissionFormatted}%
@ -261,7 +264,9 @@ export const Statistics = ({
); );
const numberOfTradersValue = data.referees.length; const numberOfTradersValue = data.referees.length;
const numberOfTradersTile = ( const numberOfTradersTile = (
<StatTile title={t('Number of traders')}>{numberOfTradersValue}</StatTile> <StatTile title={t('Number of traders')} testId="number-of-traders">
{numberOfTradersValue}
</StatTile>
); );
const codeTile = ( const codeTile = (
@ -276,6 +281,7 @@ export const Statistics = ({
title={t('myVolume', 'My volume (last {{count}} epochs)', { title={t('myVolume', 'My volume (last {{count}} epochs)', {
count: details?.windowLength || DEFAULT_AGGREGATION_DAYS, count: details?.windowLength || DEFAULT_AGGREGATION_DAYS,
})} })}
testId="my-volume"
overrideWithNoProgram={!details} overrideWithNoProgram={!details}
> >
{compactNumFormat.format(referrerVolumeValue)} {compactNumFormat.format(referrerVolumeValue)}
@ -291,6 +297,7 @@ export const Statistics = ({
count: details?.windowLength || DEFAULT_AGGREGATION_DAYS, count: details?.windowLength || DEFAULT_AGGREGATION_DAYS,
})} })}
description={<QUSDTooltip />} description={<QUSDTooltip />}
testId="total-commission"
> >
{getNumberFormat(0).format(Number(totalCommissionValue))} {getNumberFormat(0).format(Number(totalCommissionValue))}
</StatTile> </StatTile>
@ -316,6 +323,7 @@ export const Statistics = ({
const currentBenefitTierTile = ( const currentBenefitTierTile = (
<StatTile <StatTile
title={t('Current tier')} title={t('Current tier')}
testId="current-tier"
description={ description={
nextBenefitTierValue?.tier nextBenefitTierValue?.tier
? t('(Next tier: {{nextTier}})', { ? t('(Next tier: {{nextTier}})', {
@ -331,7 +339,11 @@ export const Statistics = ({
</StatTile> </StatTile>
); );
const discountFactorTile = ( const discountFactorTile = (
<StatTile title={t('Discount')} overrideWithNoProgram={!details}> <StatTile
title={t('Discount')}
testId="discount"
overrideWithNoProgram={!details}
>
{isApplyCodePreview && benefitTiers.length >= 1 {isApplyCodePreview && benefitTiers.length >= 1
? benefitTiers[0].discountFactor * 100 ? benefitTiers[0].discountFactor * 100
: discountFactorValue * 100} : discountFactorValue * 100}
@ -347,23 +359,34 @@ export const Statistics = ({
count: details?.windowLength, count: details?.windowLength,
} }
)} )}
testId="combined-volume"
overrideWithNoProgram={!details} overrideWithNoProgram={!details}
> >
{compactNumFormat.format(runningVolumeValue)} {compactNumFormat.format(runningVolumeValue)}
</StatTile> </StatTile>
); );
const epochsTile = ( const epochsTile = (
<StatTile title={t('Epochs in set')}>{epochsValue}</StatTile> <StatTile title={t('Epochs in set')} testId="epochs-in-set">
{epochsValue}
</StatTile>
); );
const nextTierVolumeTile = ( const nextTierVolumeTile = (
<StatTile title={t('Volume to next tier')} overrideWithNoProgram={!details}> <StatTile
title={t('Volume to next tier')}
testId="vol-to-next-tier"
overrideWithNoProgram={!details}
>
{nextBenefitTierVolumeValue <= 0 {nextBenefitTierVolumeValue <= 0
? '0' ? '0'
: compactNumFormat.format(nextBenefitTierVolumeValue)} : compactNumFormat.format(nextBenefitTierVolumeValue)}
</StatTile> </StatTile>
); );
const nextTierEpochsTile = ( const nextTierEpochsTile = (
<StatTile title={t('Epochs to next tier')} overrideWithNoProgram={!details}> <StatTile
title={t('Epochs to next tier')}
testId="epochs-to-next-tier"
overrideWithNoProgram={!details}
>
{nextBenefitTierEpochsValue <= 0 ? '0' : nextBenefitTierEpochsValue} {nextBenefitTierEpochsValue <= 0 ? '0' : nextBenefitTierEpochsValue}
</StatTile> </StatTile>
); );

View File

@ -32,6 +32,7 @@ export const Tile = ({
type StatTileProps = { type StatTileProps = {
title: string; title: string;
testId?: string;
description?: ReactNode; description?: ReactNode;
children?: ReactNode; children?: ReactNode;
overrideWithNoProgram?: boolean; overrideWithNoProgram?: boolean;
@ -40,6 +41,7 @@ export const StatTile = ({
title, title,
description, description,
children, children,
testId,
overrideWithNoProgram = false, overrideWithNoProgram = false,
}: StatTileProps) => { }: StatTileProps) => {
if (overrideWithNoProgram) { if (overrideWithNoProgram) {
@ -47,10 +49,15 @@ export const StatTile = ({
} }
return ( return (
<Tile> <Tile>
<h3 className="mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100 calt"> <h3
data-testid={testId}
className="mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100 calt"
>
{title} {title}
</h3> </h3>
<div className="text-5xl text-left">{children}</div> <div data-testid={`${testId}-value`} className="text-5xl text-left">
{children}
</div>
{description && ( {description && (
<div className="text-sm text-left text-vega-clight-100 dark:text-vega-cdark-100"> <div className="text-sm text-left text-vega-clight-100 dark:text-vega-cdark-100">
{description} {description}

View File

@ -6,23 +6,27 @@ from typing import Optional
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"]) WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
ASSET_NAME = "tDAI" ASSET_NAME = "tDAI"
def wait_for_toast_confirmation(page: Page, timeout: int = 30000): def wait_for_toast_confirmation(page: Page, timeout: int = 30000):
page.wait_for_function(""" page.wait_for_function("""
document.querySelector('[data-testid="toast-content"]') && document.querySelector('[data-testid="toast-content"]') &&
document.querySelector('[data-testid="toast-content"]').innerText.includes('AWAITING CONFIRMATION') document.querySelector('[data-testid="toast-content"]').innerText.includes('AWAITING CONFIRMATION')
""", timeout=timeout) """, timeout=timeout)
def create_and_faucet_wallet( def create_and_faucet_wallet(
vega: VegaServiceNull, vega: VegaServiceNull,
wallet: WalletConfig, wallet: WalletConfig,
symbol: Optional[str] = None, symbol: Optional[str] = None,
amount: float = 1e4, 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.create_key(wallet.name)
vega.mint(wallet.name, asset_id, amount) vega.mint(wallet.name, asset_id, amount)
def next_epoch(vega: VegaServiceNull): def next_epoch(vega: VegaServiceNull):
forwards = 0 forwards = 0
epoch_seq = vega.statistics().epoch_seq epoch_seq = vega.statistics().epoch_seq
@ -36,13 +40,34 @@ def next_epoch(vega: VegaServiceNull):
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
def truncate_middle(market_id, start=6, end=4): def truncate_middle(market_id, start=6, end=4):
if len(market_id) < 11: if len(market_id) < 11:
return market_id return market_id
return market_id[:start] + '\u2026' + market_id[-end:] 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("manage-vega-wallet").click()
page.get_by_test_id("key-" + vega.wallet.public_key(key_name)).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() 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

View File

@ -1,6 +1,7 @@
from typing import List, Tuple, Optional from typing import List, Tuple, Optional
from vega_sim.service import VegaService, PeggedOrder from vega_sim.service import VegaService, PeggedOrder
def submit_order( def submit_order(
vega: VegaService, vega: VegaService,
wallet_name: str, wallet_name: str,
@ -35,7 +36,7 @@ def submit_multiple_orders(
submit_order(vega, wallet_name, market_id, side, volume, price) 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( vega.submit_simple_liquidity(
key_name=wallet_name, key_name=wallet_name,
market_id=market_id, 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), pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_MID", offset=1),
wait=False, wait=False,
time_in_force="TIME_IN_FORCE_GTC", time_in_force="TIME_IN_FORCE_GTC",
volume=99, volume=buy_vol,
) )
vega.submit_order( vega.submit_order(
market_id=market_id, 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), pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_MID", offset=1),
wait=False, wait=False,
time_in_force="TIME_IN_FORCE_GTC", time_in_force="TIME_IN_FORCE_GTC",
volume=99, volume=sell_vol,
) )

View File

@ -8,12 +8,17 @@ logger = logging.getLogger()
mint_amount: float = 10e5 mint_amount: float = 10e5
market_name = "BTC:DAI_2023" market_name = "BTC:DAI_2023"
default_sell_orders = [[1, 110], [1, 105]]
default_buy_orders = [[1, 90], [1, 95]]
def setup_simple_market( def setup_simple_market(
vega: VegaService, vega: VegaService,
approve_proposal=True, approve_proposal=True,
custom_market_name=market_name, custom_market_name=market_name,
custom_asset_name="tDAI", custom_asset_name="tDAI",
custom_asset_symbol="tDAI", custom_asset_symbol="tDAI",
custom_quantum=1
): ):
for wallet in wallets: for wallet in wallets:
vega.create_key(wallet.name) vega.create_key(wallet.name)
@ -37,6 +42,7 @@ def setup_simple_market(
symbol=custom_asset_symbol, symbol=custom_asset_symbol,
decimals=5, decimals=5,
max_faucet_amount=1e10, max_faucet_amount=1e10,
quantum=custom_quantum,
) )
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
@ -111,16 +117,17 @@ def setup_simple_successor_market(
return market_id return market_id
def setup_opening_auction_market(vega: VegaService, market_id: str = None, **kwargs): 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 market_id is None or market_id not in vega.all_markets(): if not market_exists(vega, market_id):
market_id = setup_simple_market(vega, **kwargs) 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( 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( 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") vega.forward("10s")
@ -130,11 +137,22 @@ def setup_opening_auction_market(vega: VegaService, market_id: str = None, **kwa
return market_id return market_id
def setup_continuous_market(vega: VegaService, market_id: str = None, **kwargs): def market_exists(vega: VegaService, market_id: str):
if market_id is None or market_id not in vega.all_markets(): if market_id is None:
market_id = setup_opening_auction_market(vega, **kwargs) 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.forward("10s")
vega.wait_fn(1) vega.wait_fn(1)
@ -142,6 +160,7 @@ def setup_continuous_market(vega: VegaService, market_id: str = None, **kwargs):
return market_id return market_id
def setup_perps_market( def setup_perps_market(
vega: VegaService, vega: VegaService,
custom_asset_name="tDAI", custom_asset_name="tDAI",
@ -210,7 +229,7 @@ def setup_perps_market(
settlement_data_key=TERMINATE_WALLET.name, settlement_data_key=TERMINATE_WALLET.name,
funding_payment_frequency_in_seconds=10, funding_payment_frequency_in_seconds=10,
market_decimals=5, market_decimals=5,
) )
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
submit_liquidity(vega, MM_WALLET.name, market_id) submit_liquidity(vega, MM_WALLET.name, market_id)
@ -225,4 +244,4 @@ def setup_perps_market(
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
return market_id return market_id

View File

@ -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"))

View File

@ -7,6 +7,9 @@ WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
MM_WALLET = WalletConfig("market_maker", "pin") MM_WALLET = WalletConfig("market_maker", "pin")
MM_WALLET2 = WalletConfig("market_maker_2", "pin2") MM_WALLET2 = WalletConfig("market_maker_2", "pin2")
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs") 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] wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET, GOVERNANCE_WALLET]