Skip to content

Commit

Permalink
Split pool tests
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielSchiavini committed Jan 17, 2024
1 parent c5712e0 commit 56510d8
Show file tree
Hide file tree
Showing 19 changed files with 275 additions and 286 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ jobs:
matrix:
name:
- gauge
- pools
- pools/exchange
- pools/general
- pools/meta
- pools/oracle
- factory

steps:
Expand Down
Empty file.
84 changes: 84 additions & 0 deletions tests/pools/exchange/test_exchange.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import pytest

pytestmark = pytest.mark.usefixtures("initial_setup")


@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)])
def test_min_dy(
bob,
swap,
pool_type,
pool_tokens,
underlying_tokens,
pool_token_types,
metapool_token_type,
sending,
receiving,
decimals,
):
amount = 1000 * 10 ** decimals[sending]
initial_receiving = (
pool_tokens[receiving].balanceOf(bob) if pool_type == 0 else underlying_tokens[receiving].balanceOf(bob)
)

min_dy = swap.get_dy(sending, receiving, amount)
# apply rebasing for expected dy
# Down rebasing breaks dy
if pool_type == 0 and pool_token_types[sending] == 2 and sending == 1:
min_dy -= pool_tokens[sending].balanceOf(swap.address) // 1000000

swap.exchange(sending, receiving, amount, min_dy - 1, sender=bob)

if pool_type == 0:
received = pool_tokens[receiving].balanceOf(bob)
else:
received = underlying_tokens[receiving].balanceOf(bob)

if (pool_type == 0 and 2 in pool_token_types) or (pool_type == 1 and metapool_token_type == 2):
assert abs(received - min_dy - initial_receiving) == pytest.approx(1, abs=received // 1000000)
else:
assert abs(received - min_dy - initial_receiving) <= 1


@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)])
def test_min_dy_imbalanced(
bob,
swap,
pool_type,
pool_tokens,
underlying_tokens,
pool_token_types,
metapool_token_type,
sending,
receiving,
decimals,
):
amounts = [1_500_000 * 10**i for i in decimals]
scaler = amounts.copy() # used to scale token amounts when decimals are different

amounts[sending] = 0
amounts[receiving] = amounts[receiving]

swap.add_liquidity(amounts, 0, sender=bob)

# oracle
rate = 1
if pool_type == 0:
if pool_token_types[sending] == 1:
rate = rate / (pool_tokens[sending].exchangeRate() / 10**18)
if pool_token_types[receiving] == 1:
rate = rate * (pool_tokens[receiving].exchangeRate() / 10**18)

elif pool_type == 1:
if metapool_token_type == 1:
if sending == 0:
rate = rate / (underlying_tokens[0].exchangeRate() / 10**18)

if receiving == 0:
rate = rate * (underlying_tokens[0].exchangeRate() / 10**18)

# we need to scale these appropriately for tokens with different decimal values
min_dy_sending = swap.get_dy(sending, receiving, scaler[sending]) / scaler[receiving]
min_dy_receiving = swap.get_dy(receiving, sending, scaler[receiving]) / scaler[sending]

assert min_dy_sending * rate > min_dy_receiving
File renamed without changes.
79 changes: 79 additions & 0 deletions tests/pools/exchange/test_exchange_receiver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import pytest

pytestmark = pytest.mark.usefixtures("initial_setup")


def test_add_liquidity(bob, charlie, swap, deposit_amounts):
swap.add_liquidity(deposit_amounts, 0, charlie, sender=bob)

assert swap.balanceOf(bob) == 0
assert swap.balanceOf(charlie) > 0


def test_exchange(
bob, charlie, swap, pool_type, pool_tokens, underlying_tokens, decimals, pool_token_types, metapool_token_type
):
balance = pool_tokens[0].balanceOf(bob) if pool_type == 0 else underlying_tokens[0].balanceOf(bob)

swap.exchange(1, 0, 1000 * 10**18, 0, charlie, sender=bob)
if pool_type == 0:
assert pool_tokens[0].balanceOf(charlie) > 0
if pool_token_types[0] != 2:
assert pool_tokens[0].balanceOf(bob) == balance
else:
assert pool_tokens[0].balanceOf(bob) == pytest.approx(balance, rel=2e-2)
else:
assert underlying_tokens[0].balanceOf(charlie) > 0
if metapool_token_type != 2:
assert underlying_tokens[0].balanceOf(bob) == balance
else:
assert underlying_tokens[0].balanceOf(bob) == pytest.approx(balance, rel=2e-2)


def test_remove_liquidity(
bob, swap, charlie, pool_type, pool_tokens, underlying_tokens, initial_amounts, pool_size, deposit_amounts
):
swap.add_liquidity(deposit_amounts, 0, sender=bob)
initial_amount = swap.balanceOf(bob)
withdraw_amount = initial_amount // 4
swap.remove_liquidity(withdraw_amount, [0] * pool_size, charlie, sender=bob)

i = 0
if pool_type == 0:
for coin, amount in zip(pool_tokens, deposit_amounts):
assert coin.balanceOf(swap) + coin.balanceOf(charlie) == pytest.approx(deposit_amounts[0] * 2, rel=1.5e-2)
i += 1
else:
for coin, amount in zip(underlying_tokens[:2], deposit_amounts):
assert coin.balanceOf(swap) + coin.balanceOf(charlie) == pytest.approx(deposit_amounts[0] * 2, rel=1.5e-2)
i += 1

assert swap.balanceOf(bob) == pytest.approx(deposit_amounts[0] * pool_size - withdraw_amount, rel=1.5e-2)
assert swap.totalSupply() == pytest.approx(deposit_amounts[0] * 2 * pool_size - withdraw_amount, rel=1.5e-2)


def test_remove_imbalanced(
bob, swap, charlie, pool_type, pool_tokens, underlying_tokens, initial_amounts, deposit_amounts
):
swap.add_liquidity(deposit_amounts, 0, sender=bob)
balance = swap.balanceOf(bob)
amounts = [i // 4 for i in initial_amounts]
swap.remove_liquidity_imbalance(amounts, balance, charlie, sender=bob)

if pool_type == 0:
for i, coin in enumerate(pool_tokens):
assert coin.balanceOf(charlie) == pytest.approx(amounts[i], rel=1.5e-2)
assert coin.balanceOf(swap) == pytest.approx(initial_amounts[i] - amounts[i], rel=1.5e-2)
else:
for i, coin in enumerate(underlying_tokens[:2]):
assert coin.balanceOf(charlie) == pytest.approx(amounts[i], rel=1.5e-2)
assert coin.balanceOf(swap) == pytest.approx(initial_amounts[i] - amounts[i], rel=1.5e-2)

assert swap.balanceOf(bob) / balance == pytest.approx(0.5, rel=1.5e-2)


def test_remove_one_coin(alice, charlie, swap, pool_tokens, underlying_tokens):
swap.remove_liquidity_one_coin(10**18, 0, 0, charlie, sender=alice)

assert swap.balanceOf(charlie) == 0
assert swap.balanceOf(alice) > 0
69 changes: 69 additions & 0 deletions tests/pools/exchange/test_exchange_reverts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import boa
import pytest

pytestmark = pytest.mark.usefixtures("initial_setup")


@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)])
def test_insufficient_balance(charlie, pool_tokens, underlying_tokens, swap, sending, receiving, decimals):
amount = 10 ** decimals[sending]

for token in pool_tokens + underlying_tokens:
assert token.balanceOf(charlie) == 0

# Charlie doesn't have any tokens, all balances are 0
try:
swap.exchange(sending, receiving, amount + 1, 0, sender=charlie)
assert False
except: # noqa: E722
assert True


@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)])
@pytest.mark.contains_rebasing_tokens
def test_zero_amount_swap(charlie, pool_tokens, underlying_tokens, swap, sending, receiving, decimals):
with boa.reverts():
swap.exchange(sending, receiving, 0, 0, sender=charlie)


@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)])
def test_min_dy_too_high(bob, swap, sending, receiving, decimals):
amount = 10 ** decimals[sending]
min_dy = swap.get_dy(sending, receiving, amount)
with boa.reverts():
swap.exchange(sending, receiving, amount, min_dy + 2, sender=bob)


@pytest.mark.parametrize("idx", range(2))
def test_same_coin(bob, swap, idx):
with boa.reverts():
swap.exchange(idx, idx, 0, 0, sender=bob)


@pytest.mark.parametrize("idx", [-1, -(2**127)])
def test_i_below_zero(bob, swap, idx):
with boa.reverts():
swap.exchange(idx, 0, 0, 0, sender=bob)


@pytest.mark.parametrize("idx", [9, 2**127 - 1])
def test_i_above_n_coins(bob, swap, idx):
with boa.reverts():
swap.exchange(idx, 0, 0, 0, sender=bob)


@pytest.mark.parametrize("idx", [-1, -(2**127)])
def test_j_below_zero(bob, swap, idx):
with boa.reverts():
swap.exchange(0, idx, 0, 0, sender=bob)


@pytest.mark.parametrize("idx", [9, 2**127 - 1])
def test_j_above_n_coins(bob, swap, idx):
with boa.reverts():
swap.exchange(0, idx, 0, 0, sender=bob)


def test_nonpayable(swap, bob):
with boa.reverts():
swap.exchange(0, 1, 0, 0, sender=bob, value=1)
Empty file added tests/pools/general/__init__.py
Empty file.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def pool_erc20_tokens(asset, token_b, token_c):
return [asset, token_b, token_c]


@pytest.fixture(scope="session")
@pytest.fixture()
def asset_types(pool_tokens):
_asset_types = []
for token in pool_tokens:
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import boa
import pytest
from boa.test import strategy
from hypothesis import given, settings
from hypothesis import HealthCheck, given, settings

from tests.utils import approx
from tests.utils.tokens import mint_for_testing
Expand Down Expand Up @@ -132,7 +132,10 @@ def test_price_ema_remove_imbalance(swap, alice, dt0, dt, pool_size, deposit_amo
check_oracle(swap, dt)


@given(amount=strategy("uint256", min_value=10**9, max_value=10**15))
@given(
amount=strategy("uint256", min_value=10**9, max_value=10**15),
suppress_health_check=HealthCheck.function_scoped_fixture,
)
@settings(**SETTINGS)
def test_manipulate_ema(basic_swap, bob, pool_tokens, underlying_tokens, decimals, amount):
# calc amount in:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
20 changes: 9 additions & 11 deletions tests/pools/meta/test_exchange_underlying.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,28 @@
pytestmark = pytest.mark.usefixtures("initial_setup")


@pytest.mark.skip_oracle_tokens
@pytest.mark.skip_rebasing_tokens
@pytest.mark.only_plain_tokens
@pytest.mark.parametrize("sending,receiving", filter(lambda k: 0 in k, itertools.permutations(range(4), 2)))
def test_amounts(bob, meta_swap, underlying_tokens, sending, receiving, meta_decimals, base_pool_decimals):
def test_amounts(bob, meta_swap, metapool_token, sending, receiving, meta_decimals, base_pool_decimals):
underlying_decimals = [meta_decimals] + base_pool_decimals
underlying_tokens = [underlying_tokens[0], *underlying_tokens[2:]]
metapool_token = [metapool_token[0], *metapool_token[2:]]
amount_sent = 10 ** underlying_decimals[sending]

if sending > 0 and underlying_tokens[sending].balanceOf(bob) < amount_sent:
underlying_tokens[sending]._mint_for_testing(bob, amount_sent)
if sending > 0 and metapool_token[sending].balanceOf(bob) < amount_sent:
metapool_token[sending]._mint_for_testing(bob, amount_sent)

expected_received = meta_swap.get_dy_underlying(sending, receiving, amount_sent)
received_true = meta_swap.exchange_underlying(sending, receiving, amount_sent, 0, sender=bob) # noqa: F841
assert approx(received_true, expected_received, 1e-3)


@pytest.mark.skip_rebasing_tokens
@pytest.mark.skip_oracle_tokens
@pytest.mark.only_plain_tokens
@pytest.mark.parametrize("sending,receiving", itertools.permutations(range(4), 2))
def test_min_dy_underlying(bob, meta_swap, underlying_tokens, sending, receiving, meta_decimals, base_pool_decimals):
def test_min_dy_underlying(bob, meta_swap, metapool_token, sending, receiving, meta_decimals, base_pool_decimals):
underlying_decimals = [meta_decimals] + base_pool_decimals
underlying_tokens = [underlying_tokens[0], *underlying_tokens[2:]]
metapool_token = [metapool_token[0], *metapool_token[2:]]
amount = 10 ** underlying_decimals[sending]
underlying_tokens[sending]._mint_for_testing(bob, amount, sender=bob)
metapool_token[sending]._mint_for_testing(bob, amount, sender=bob)

expected = meta_swap.get_dy_underlying(sending, receiving, amount)
received = meta_swap.exchange_underlying(sending, receiving, amount, 0, sender=bob)
Expand Down
55 changes: 24 additions & 31 deletions tests/pools/oracle/test_oracle.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,32 @@
DEPOSIT_AMOUNT = INITIAL_AMOUNT // 100


@pytest.fixture(scope="module")
def initial_setup_alice(
alice,
deposit_amounts,
swap,
pool_type,
base_pool,
base_oracle_tokens,
base_pool_decimals,
base_pool_lp_token,
initial_balance,
initial_amounts,
oracle_tokens,
underlying_tokens,
):
with boa.env.anchor():
mint_for_testing(alice, 1 * 10**18, None, True)
@pytest.fixture()
def initial_setup_alice(pool_type, basic_setup_alice, meta_setup_alice):
if pool_type == 0:
return basic_setup_alice
return meta_setup_alice

if pool_type == 0:
mint_account(alice, oracle_tokens, initial_balance, initial_amounts)
with boa.env.prank(alice):
for token in oracle_tokens:
token.approve(swap.address, 2**256 - 1)

else:
add_base_pool_liquidity(alice, base_pool, base_oracle_tokens, base_pool_decimals)
mint_for_testing(alice, initial_amounts[0], underlying_tokens[0], False)
@pytest.fixture()
def basic_setup_alice(alice, initial_amounts, initial_balance, oracle_tokens, basic_swap):
mint_for_testing(alice, 1 * 10**18, None, True)
mint_account(alice, oracle_tokens, initial_balance, initial_amounts)
with boa.env.prank(alice):
for token in oracle_tokens:
token.approve(basic_swap.address, 2**256 - 1)

with boa.env.prank(alice):
for token in underlying_tokens:
token.approve(swap.address, 2**256 - 1)

yield
@pytest.fixture()
def meta_setup_alice(
alice, base_pool_tokens, base_pool, base_pool_decimals, initial_amounts, meta_swap, underlying_tokens
):
mint_for_testing(alice, 1 * 10**18, None, True)
add_base_pool_liquidity(alice, base_pool, base_pool_tokens, base_pool_decimals)
mint_for_testing(alice, initial_amounts[0], underlying_tokens[0], False)
with boa.env.prank(alice):
for token in underlying_tokens:
token.approve(meta_swap.address, 2**256 - 1)


def test_initial_liquidity(
Expand Down Expand Up @@ -79,8 +72,8 @@ def test_initial_liquidity(
assert swap.admin_balances(1) == 0


def test_oracles(alice, swap, pool_size, pool_type, pool_token_types, metapool_token_type):
assert swap._storage.oracles.get() != [0] * pool_size
def test_oracles(alice, swap, pool_size):
assert swap._immutables.rate_oracles.get() != [0] * pool_size


def test_get_dy(
Expand Down
Loading

0 comments on commit 56510d8

Please sign in to comment.