Skip to content

Commit

Permalink
feat: add aerodrome fwd-looking apys (yearn#623)
Browse files Browse the repository at this point in the history
* add: aero fwd calcs

* add: aero voter

* init: aero

* update vaults for aero

* update velo registry to voter
  • Loading branch information
0xBasically authored Sep 12, 2023
1 parent a48edd3 commit 87f0ce1
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 6 deletions.
2 changes: 1 addition & 1 deletion yearn/apy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from yearn.apy import v1, v2, velo
from yearn.apy import v1, v2, velo, aero
from yearn.apy.common import (Apy, ApyBlocks, ApyError, ApyFees, ApyPoints,
ApySamples, get_samples)
from yearn.apy.curve import simple as curve
60 changes: 60 additions & 0 deletions yearn/apy/aero.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import logging
import os
from pprint import pformat
from time import time
from typing import TYPE_CHECKING, Optional

from async_lru import alru_cache
from brownie import ZERO_ADDRESS, chain
from y import Contract, Network, magic
from y.time import get_block_timestamp_async

from yearn.apy.common import SECONDS_PER_YEAR, Apy, ApyFees, ApyPoints, ApySamples
from yearn.debug import Debug

if TYPE_CHECKING:
from yearn.v2.vaults import Vault

logger = logging.getLogger(__name__)

COMPOUNDING = 365

voter = Contract("0x16613524e02ad97eDfeF371bC883F2F5d6C480A5") if Network(chain.id) == Network.Base else None

@alru_cache
async def get_staking_pool(underlying: str) -> Optional[Contract]:
if Network(chain.id) == Network.Base:
staking_pool = await voter.gauges.coroutine(underlying)
return None if staking_pool == ZERO_ADDRESS else await Contract.coroutine(staking_pool)

async def staking(vault: "Vault", staking_rewards: Contract, samples: ApySamples, block: Optional[int]=None) -> float:
if len(vault.strategies) == 0:
return Apy("v2:aero_no_strats", 0, 0, ApyFees(0, 0), ApyPoints(0, 0, 0))

end = await staking_rewards.periodFinish.coroutine(block_identifier=block)
current_time = time() if block is None else await get_block_timestamp_async(block)
total_supply = await staking_rewards.totalSupply.coroutine(block_identifier=block) if hasattr(staking_rewards, "totalSupply") else 0
rate = await staking_rewards.rewardRate.coroutine(block_identifier=block) if hasattr(staking_rewards, "rewardRate") else 0
performance = await vault.vault.performanceFee.coroutine(block_identifier=block) / 1e4 if hasattr(vault.vault, "performanceFee") else 0
management = await vault.vault.managementFee.coroutine(block_identifier=block) / 1e4 if hasattr(vault.vault, "managementFee") else 0
# since its a fork we still call it keepVELO
keep = await vault.strategies[0].strategy.localKeepVELO.coroutine(block_identifier=block) / 1e4 if hasattr(vault.strategies[0].strategy, "localKeepVELO") else 0
rate = rate * (1 - keep)
fees = ApyFees(performance=performance, management=management, keep_velo=keep)

if end < current_time or total_supply == 0 or rate == 0:
return Apy("v2:aero_unpopular", gross_apr=0, net_apy=0, fees=fees)
pool_price = await magic.get_price(vault.token.address, block=block, sync=False)
reward_token = await staking_rewards.rewardToken.coroutine(block_identifier=block) if hasattr(staking_rewards, "rewardToken") else None
token = reward_token
token_price = await magic.get_price(token, block=block, sync=False)

gross_apr = (SECONDS_PER_YEAR * (rate / 1e18) * token_price) / (pool_price * (total_supply / 1e18))

net_apr = gross_apr * (1 - performance) - management
net_apy = (1 + (net_apr / COMPOUNDING)) ** COMPOUNDING - 1
from yearn.apy.staking_rewards import get_staking_rewards_apr
staking_rewards_apr = await get_staking_rewards_apr(vault, samples)
if os.getenv("DEBUG", None):
logger.info(pformat(Debug().collect_variables(locals())))
return Apy("v2:aero", gross_apr=gross_apr, net_apy=net_apy, fees=fees, staking_rewards_apr=staking_rewards_apr)
7 changes: 2 additions & 5 deletions yearn/apy/velo.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@

COMPOUNDING = 365

registry = Contract("0x41c914ee0c7e1a5edcd0295623e6dc557b5abf3c") if Network(chain.id) == Network.Optimism else None
voter = Contract("0x41c914ee0c7e1a5edcd0295623e6dc557b5abf3c") if Network(chain.id) == Network.Optimism else None

@alru_cache
async def get_staking_pool(underlying: str) -> Optional[Contract]:
if Network(chain.id) == Network.Optimism:
staking_pool = await registry.gauges.coroutine(underlying)
staking_pool = await voter.gauges.coroutine(underlying)
return None if staking_pool == ZERO_ADDRESS else await Contract.coroutine(staking_pool)

async def staking(vault: "Vault", staking_rewards: Contract, samples: ApySamples, block: Optional[int]=None) -> float:
Expand All @@ -43,9 +43,6 @@ async def staking(vault: "Vault", staking_rewards: Contract, samples: ApySamples

if end < current_time or total_supply == 0 or rate == 0:
return Apy("v2:velo_unpopular", gross_apr=0, net_apy=0, fees=fees)
# hardcode frxETH-sfrxETH to frxETH-WETH price for now
if vault.vault.address == "0xc2626aCEdc27cFfB418680d0307C9178955A4743":
pool_price = await magic.get_price("0x3f42Dc59DC4dF5cD607163bC620168f7FF7aB970", block=block, sync=False)
else:
pool_price = await magic.get_price(vault.token.address, block=block, sync=False)
reward_token = await staking_rewards.rewardToken.coroutine(block_identifier=block) if hasattr(staking_rewards, "rewardToken") else None
Expand Down
2 changes: 2 additions & 0 deletions yearn/v2/vaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ async def apy(self, samples: "ApySamples"):
return await apy.curve.simple(self, samples)
elif pool := await apy.velo.get_staking_pool(self.token.address):
return await apy.velo.staking(self, pool, samples)
elif pool := await apy.aero.get_staking_pool(self.token.address):
return await apy.aero.staking(self, pool, samples)
elif Version(self.api_version) >= Version("0.3.2"):
return await apy.v2.average(self, samples)
else:
Expand Down

0 comments on commit 87f0ce1

Please sign in to comment.