Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from ape to boa #14

Merged
merged 19 commits into from
Dec 12, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Handle more test errors
DanielSchiavini committed Nov 29, 2023
commit 620bfe4062e3dbd14f5a7d70a66b00f8d1891bef
3 changes: 0 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -21,6 +21,3 @@ repos:
hooks:
- id: isort
args: ["--profile", "black", --line-length=79]

default_language_version:
python: python3.11
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ Mainnet:

1. Curve Stable Registry: A registry of custom pool implementations deployed by Curve Core.
2. Curve Stable Factory: A permissionless [StableSwap](https://curve.fi/files/stableswap-paper.pdf) pool factory, which also acts as a registry for pools that its users create.
3. Curve Crypto Registry: A registry of custom CryptoSwap pool implementaions deployed by Curve Core.
3. Curve Crypto Registry: A registry of custom CryptoSwap pool implementations deployed by Curve Core.
4. Curve Crypto Factory: A permissionless [CryptoSwap](https://curve.fi/files/crypto-pools-paper.pdf) pool factory, which also acts as a registry for pools that its users create.

Each of the child registries are accompanied by a RegistryHandler, which is a contract that wraps around the child registry and enforces the abi implemented in the MetaRegistry. These registry handlers are then added to the MetaRegistry using the `MetaRegistry.add_registry_handler` method.
@@ -67,9 +67,9 @@ Out[1]: '3pool'

#### `MetaRegistry.is_meta`

Metapools are pools that pair a coin to a base pool comprising of multiple coins.
Meta-pools are pools that pair a coin to a base pool comprising multiple coins.

An example is the [`LUSD-3CRV`](https://etherscan.io/address/0xed279fdd11ca84beef15af5d39bb4d4bee23f0ca) pool which pairs [Liquity's](https://www.liquity.org/) [`LUSD`](https://etherscan.io/address/0x5f98805a4e8be255a32880fdec7f6728c6568ba0) against [`3CRV`](https://etherscan.io/address/0x6c3f90f043a72fa612cbac8115ee7e52bde6e490), where `3CRV` is a liquidity pool token that represents a share of a pool containing `DAI`, `USDC` and `USDT`:
An example is the [`LUSD-3CRV`](https://etherscan.io/address/0xed279fdd11ca84beef15af5d39bb4d4bee23f0ca) pool which pairs [Liquidity's](https://www.liquity.org/) [`LUSD`](https://etherscan.io/address/0x5f98805a4e8be255a32880fdec7f6728c6568ba0) against [`3CRV`](https://etherscan.io/address/0x6c3f90f043a72fa612cbac8115ee7e52bde6e490), where `3CRV` is a liquidity pool token that represents a share of a pool containing `DAI`, `USDC` and `USDT`:

```
In [1]: metaregistry.is_meta("0xed279fdd11ca84beef15af5d39bb4d4bee23f0ca")
@@ -294,7 +294,7 @@ For CryptoSwap, the getter returns:
4. Allowed extra profit
5. Fee gamma
6. Adjustment step
7. MA (moving average) half time
7. MA (moving average) half-time

```

@@ -338,7 +338,7 @@ Out[1]: '0xc4AD29ba4B3c580e6D59105FFf484999997675Ff'

#### `MetaRegistry.get_pool_asset_type`

Gets the asset type of a pool. `0` = `USD`, `1` = `ETH`, `2` = `BTC`, `3` = Other, `4` = CryptoPool token. The asset type is a property of StableSwaps, and is not enforced in CryptoSwap pools (which always return `4`).
Gets the asset type of pool. `0` = `USD`, `1` = `ETH`, `2` = `BTC`, `3` = Other, `4` = CryptoPool token. The asset type is a property of StableSwaps, and is not enforced in CryptoSwap pools (which always return `4`).

StableSwap pool example for `LUSD-3CRV` pool which is a `USD` stablecoin pool:

7 changes: 6 additions & 1 deletion scripts/change_registry_handler.py
Original file line number Diff line number Diff line change
@@ -3,7 +3,12 @@
import boa
from rich.console import Console as RichConsole

from scripts.deployment_utils import setup_environment, ZERO_ADDRESS, get_deployed_contract
from scripts.deployment_utils import (
ADDRESS_PROVIDER,
ZERO_ADDRESS,
get_deployed_contract,
setup_environment,
)

RICH_CONSOLE = RichConsole(file=sys.stdout)
CRYPTO_REGISTRY_HANDLER = "0x5f493fEE8D67D3AE3bA730827B34126CFcA0ae94"
1 change: 1 addition & 0 deletions scripts/deployment_utils.py
Original file line number Diff line number Diff line change
@@ -36,6 +36,7 @@ def setup_environment(console: RichConsole):
boa.env.eoa = FIDDY_DEPLOYER
return False


def get_deployed_contract(contract_name: str, address: str) -> VyperContract:
"""
Loads a contract and retrieves a deployed instance of it with the given address.
6 changes: 5 additions & 1 deletion scripts/setup_metaregistry.py
Original file line number Diff line number Diff line change
@@ -13,7 +13,11 @@
import boa
from rich.console import Console as RichConsole

from scripts.deployment_utils import ZERO_ADDRESS, get_deployed_contract, setup_environment
from scripts.deployment_utils import (
ZERO_ADDRESS,
get_deployed_contract,
setup_environment,
)

RICH_CONSOLE = RichConsole(file=sys.stdout)

29 changes: 19 additions & 10 deletions tests/mainnet/metaregistry/api/test_find_pool_for_coins.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import itertools
from itertools import combinations
from os import environ

import pytest

from tests.utils import ZERO_ADDRESS

@@ -11,10 +14,14 @@ def _get_all_combinations(metaregistry, pool):
pool_coins = [
coin for coin in metaregistry.get_coins(pool) if coin != ZERO_ADDRESS
]
all_combinations = list(itertools.combinations(pool_coins, 2))
all_combinations = list(combinations(pool_coins, 2))
first_coin = pool_coins[0]

if metaregistry.is_meta(pool):
# there exist some pools with an LP token as the first coin, that's incorrect
# example: 0xf5d5305790c1af08e9df44b30a1afe56ccda72df
is_first_coin_lp_token = metaregistry.get_pool_from_lp_token(first_coin)

if metaregistry.is_meta(pool) and not is_first_coin_lp_token:
underlying_coins = [
coin
for coin in metaregistry.get_underlying_coins(pool)
@@ -29,16 +36,18 @@ def _get_all_combinations(metaregistry, pool):
return all_combinations


@pytest.mark.skipif(
condition=environ.get("TEST_ALL") == "False",
reason="This test is too slow, don't run it locally every time.",
)
def test_all(populated_metaregistry, pool):
combinations = _get_all_combinations(populated_metaregistry, pool)
for combination in combinations:
all_combinations = _get_all_combinations(populated_metaregistry, pool)
for coin1, coin2 in all_combinations:
pools_containing_pair = populated_metaregistry.find_pools_for_coins(
*combination
coin1, coin2
)
assert pool in pools_containing_pair

for i, found_pool in enumerate(pools_containing_pair):
assert (
populated_metaregistry.find_pool_for_coins(*combination, i)
== found_pool
)
pool = populated_metaregistry.find_pool_for_coins(coin1, coin2, i)
assert pool == found_pool
27 changes: 6 additions & 21 deletions tests/mainnet/metaregistry/api/test_get_admin_balances.py
Original file line number Diff line number Diff line change
@@ -3,7 +3,11 @@
from boa import BoaError
from eth.codecs.abi.exceptions import DecodeError as ABIDecodeError

from tests.utils import ZERO_ADDRESS, get_deployed_token_contract
from tests.utils import (
assert_negative_coin_balance,
check_decode_error,
get_deployed_token_contract,
)


def pre_test_checks(metaregistry, pool):
@@ -29,31 +33,12 @@ def pre_test_checks(metaregistry, pool):
if contract.totalSupply() == 0:
return pytest.skip("LP token supply is zero")
except ABIDecodeError as e:
assert e.msg == "Value length is not the expected size of 32 bytes"
assert len(e.value) == 4096
check_decode_error(e)
return pytest.skip(
f"Pool {pool} cannot decode the total supply of its LP token {lp_token}"
)


def assert_negative_coin_balance(metaregistry, pool):
"""
The implementation of get_balance calculates (balance - admin_balance) but sometimes the coin
balance might be lower than the admin balance, resulting in an uint underflow.
"""
coins = [
coin for coin in metaregistry.get_coins(pool) if coin != ZERO_ADDRESS
]
coin_balances = [
get_deployed_token_contract(coin).balanceOf(pool) for coin in coins
]
admin_balances = metaregistry.get_admin_balances(pool)
assert any(
coin_balance < admin_balance
for coin_balance, admin_balance in zip(coin_balances, admin_balances)
)


def test_stable_registry_pools(
populated_metaregistry, stable_registry_pool, stable_registry
):
Original file line number Diff line number Diff line change
@@ -17,7 +17,6 @@

def _test_underlying_decimals_getter(metaregistry, registry, pool):
metaregistry_output = metaregistry.get_underlying_decimals(pool)
assert metaregistry_output[1] != 0 # there has to be a second coin!

pool_is_metapool = metaregistry.is_meta(pool)
if pool in EXCEPTIONS:
61 changes: 39 additions & 22 deletions tests/mainnet/metaregistry/api/test_get_virtual_price.py
Original file line number Diff line number Diff line change
@@ -3,8 +3,14 @@
import boa
import pytest
from boa import BoaError
from eth.codecs.abi.exceptions import DecodeError as ABIDecodeError

from tests.utils import ZERO_ADDRESS, get_deployed_token_contract
from tests.utils import (
ZERO_ADDRESS,
assert_negative_coin_balance,
check_decode_error,
get_deployed_token_contract,
)

# ---- sanity checks since vprice getters can revert for specific pools states ----

@@ -36,18 +42,21 @@ def _check_skem_tokens_with_weird_decimals(

pool_balances_float.append(pool_balances[i] / 10 ** coin_decimals[i])

if (
coin_decimals[i] == 0
and get_deployed_token_contract(
metaregistry.get_coins(pool)[0]
).decimals()
== 0
):
with boa.reverts():
first_coin = metaregistry.get_coins(pool)[0]
coin_contract = get_deployed_token_contract(first_coin)
if coin_decimals[i] == 0 and coin_contract.decimals() == 0:
try:
virtual_price = metaregistry.get_virtual_price_from_lp_token(
lp_token
)
warnings.warn(
f"Pool {pool} virtual price {virtual_price}. continuing test"
)
except BoaError:
metaregistry.get_virtual_price_from_lp_token(lp_token)
pytest.skip(
f"skem token {coins[i]} in pool {pool} with zero decimals"
)
pytest.skip(
f"Skem token {coins[i]} in pool {pool} with zero decimals"
)

return pool_balances_float

@@ -69,23 +78,26 @@ def _check_pool_is_depegged(
and min(pool_balances_float) < 1
):
try:
with boa.reverts():
metaregistry.get_virtual_price_from_lp_token(lp_token)

virtual_price = metaregistry.get_virtual_price_from_lp_token(
lp_token
)
warnings.warn(
f"Pool {pool} virtual price {virtual_price}. continuing test"
)
except BoaError:
pytest.skip(
f"skewed pool: {pool} as num coins (decimals divided) at index {i} is "
f"{pool_balances[i] / 10 ** coin_decimals[i]}"
)
except (
AssertionError
): # ok to catch this assertion error since we continue testing
warnings.warn(
"pool virtual price getter did not revert. continuing test"
)


def pre_test_checks(metaregistry, pool):
pool_balances = metaregistry.get_balances(pool)
try:
pool_balances = metaregistry.get_balances(pool)
except BoaError:
assert_negative_coin_balance(metaregistry, pool)
return pytest.skip(f"Pool {pool} has coin balances lower than admin")

lp_token = metaregistry.get_lp_token(pool)

_check_pool_has_no_liquidity(metaregistry, pool, pool_balances, lp_token)
@@ -139,6 +151,11 @@ def test_stable_factory_pools(
except BoaError:
with boa.reverts():
populated_metaregistry.get_virtual_price_from_lp_token(lp_token)
except ABIDecodeError as e:
check_decode_error(e)
return pytest.skip(
f"Pool {stable_factory_pool} cannot decode the virtual price"
)


def test_crypto_registry_pools(
29 changes: 29 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@

import boa
from boa.vyper.contract import VyperContract
from eth.codecs.abi.exceptions import DecodeError as ABIDecodeError
from eth_account.signers.local import LocalAccount

ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
@@ -98,3 +99,31 @@ def get_deployed_token_contract(address: str) -> VyperContract:
]
)
return boa.loads_abi(abi).at(address)


def check_decode_error(e: ABIDecodeError):
"""
Checks that the error message is the expected decode error.
This seems to be happening in some pools, but it's not clear if it's a boa or contract issue.
:param e: The error to check.
"""
assert e.msg == "Value length is not the expected size of 32 bytes"
assert len(e.value) == 4096


def assert_negative_coin_balance(metaregistry, pool):
"""
The implementation of get_balance calculates (balance - admin_balance) but sometimes the coin
balance might be lower than the admin balance, resulting in an uint underflow.
"""
coins = [
coin for coin in metaregistry.get_coins(pool) if coin != ZERO_ADDRESS
]
coin_balances = [
get_deployed_token_contract(coin).balanceOf(pool) for coin in coins
]
admin_balances = metaregistry.get_admin_balances(pool)
assert any(
coin_balance < admin_balance
for coin_balance, admin_balance in zip(coin_balances, admin_balances)
)