Skip to content

Commit

Permalink
fix: ycrv pricing error due to spammy pools
Browse files Browse the repository at this point in the history
  • Loading branch information
wavey0x committed Dec 9, 2022
1 parent f14e48a commit 0ceadca
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 31 deletions.
52 changes: 25 additions & 27 deletions yearn/prices/curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ def get_decimals(self, pool: AddressOrContract) -> List[int]:

return [dec for dec in decimals if dec != 0]

def get_balances(self, pool: AddressOrContract, block: Optional[Block] = None) -> Dict[EthAddress,float]:
def get_balances(self, pool: AddressOrContract, block: Optional[Block] = None, should_raise_err: bool = True) -> Optional[Dict[EthAddress,float]]:
"""
Get {token: balance} of liquidity in the pool.
"""
Expand All @@ -358,7 +358,9 @@ def get_balances(self, pool: AddressOrContract, block: Optional[Block] = None) -
)

if not any(balances):
raise ValueError(f'could not fetch balances {pool} at {block}')
if should_raise_err:
raise ValueError(f'could not fetch balances {pool} at {block}')
return None

return {
coin: balance / 10 ** dec
Expand Down Expand Up @@ -402,33 +404,29 @@ def get_price(self, token: AddressOrContract, block: Optional[Block] = None) ->
return 0
return tvl / supply

# approximate by using the most common base token we find
coins = self.get_underlying_coins(pool)
try:
coin = (set(coins) & BASIC_TOKENS).pop()
except KeyError:
coin = coins[0]

try:
virtual_price = self.get_virtual_price(pool, block)
if virtual_price:
return virtual_price * magic.get_price(coin, block)
return sum([balance * magic.get_price(coin, block) for coin, balance in self.get_balances(pool, block).items()])
except ValueError as e:
logger.warn(f'ValueError: {str(e)}')
if 'No data was returned' in str(e):
return None
else:
raise

def get_coin_price(self, token: AddressOrContract, block: Optional[Block] = None) -> Optional[float]:

# Get the pool
if len(self.coin_to_pools[token]) == 1:
pool = self.coin_to_pools[token][0]
else:
# TODO: handle this sitch if necessary
# Select the most appropriate pool
pools = self.coin_to_pools[token]
if not pools:
return
elif len(pools) == 1:
pool = pools[0]
else:
# We need to find the pool with the deepest liquidity
balances = [self.get_balances(pool, block, should_raise_err=False) for pool in pools]
balances = [bal for bal in balances if bal]
deepest_pool, deepest_bal = None, 0
for pool, pool_bals in zip(pools, balances):
if isinstance(pool_bals, Exception):
if str(pool_bals).startswith("could not fetch balances"):
continue
raise pool_bals
for _token, bal in pool_bals.items():
if _token == token and bal > deepest_bal:
deepest_pool = pool
deepest_bal = bal
pool = deepest_pool

# Get the index for `token`
coins = self.get_coins(pool)
Expand Down Expand Up @@ -539,4 +537,4 @@ def calculate_apy(self, gauge: Contract, lp_token: AddressOrContract, block: Opt
try:
curve = CurveRegistry()
except UnsupportedNetwork:
pass
pass
5 changes: 5 additions & 0 deletions yearn/prices/magic.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ def find_price(
# no liquidity for curve pool (yvecrv-f) -> return 0
elif token == "0x7E46fd8a30869aa9ed55af031067Df666EfE87da" and block < 14987514:
return 0
# no continuous price data before 2020-10-10
elif token == "0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D" and block < 11024342:
return 0

markets = [
chainlink,
Expand Down Expand Up @@ -142,11 +145,13 @@ def find_price(
return price * get_price(underlying, block=block)

if price is None and token in curve.curve.coin_to_pools:
logger.debug(f'Curve.get_coin_price -> {price}')
price = curve.curve.get_coin_price(token, block = block)

if price is None and return_price_during_vault_downtime:
for incident in INCIDENTS[token]:
if incident['start'] <= block <= incident['end']:
logger.debug(f"incidents -> {price}")
return incident['result']

if price is None:
Expand Down
8 changes: 4 additions & 4 deletions yearn/prices/synthetix.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ def __init__(self) -> None:
self.synths = self.load_synths()
logger.info(f'loaded {len(self.synths)} synths')

@lru_cache(maxsize=None)
def get_address(self, name: str) -> EthAddress:
@lru_cache(maxsize=128)
def get_address(self, name: str, block: Block = None) -> EthAddress:
"""
Get contract from Synthetix registry.
See also https://docs.synthetix.io/addresses/
"""
address_resolver = contract(addresses[chain.id])
address = address_resolver.getAddress(encode_single('bytes32', name.encode()))
address = address_resolver.getAddress(encode_single('bytes32', name.encode()), block_identifier=block)
proxy = contract(address)
return contract(proxy.target()) if hasattr(proxy, 'target') else proxy

Expand Down Expand Up @@ -73,9 +73,9 @@ def get_price(self, token: Address, block: Optional[Block] = None) -> Optional[f
"""
Get a price of a synth in dollars.
"""
rates = self.get_address('ExchangeRates')
key = self.get_currency_key(token)
try:
rates = self.get_address('ExchangeRates', block=block)
return rates.rateForCurrency(key, block_identifier=block) / 1e18
except ValueError:
return None
Expand Down

0 comments on commit 0ceadca

Please sign in to comment.