Пример #1
0
    def apy(self, _: ApySamples) -> Apy:
        curve_3_pool = contract("0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7")
        curve_reward_distribution = contract(
            "0xA464e6DCda8AC41e03616F95f4BC98a13b8922Dc")
        curve_voting_escrow = contract(
            "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2")
        voter = "0xF147b8125d2ef93FB6965Db97D6746952a133934"
        crv_price = magic.get_price(
            "0xD533a949740bb3306d119CC777fa900bA034cd52")
        yvecrv_price = magic.get_price(
            "0xc5bDdf9843308380375a611c18B50Fb9341f502A")

        total_vecrv = curve_voting_escrow.totalSupply()
        yearn_vecrv = curve_voting_escrow.balanceOf(voter)
        vault_supply = self.vault.totalSupply()

        week = 7 * 86400
        epoch = math.floor(time() / week) * week - week
        tokens_per_week = curve_reward_distribution.tokens_per_week(
            epoch) / 1e18
        virtual_price = curve_3_pool.get_virtual_price() / 1e18
        # although we call this APY, this is actually APR since there is no compounding
        apy = (tokens_per_week * virtual_price * 52) / (
            (total_vecrv / 1e18) * crv_price)
        vault_boost = (yearn_vecrv / vault_supply) * (crv_price / yvecrv_price)
        composite = {
            "currentBoost": vault_boost,
            "boostedApy": apy * vault_boost,
            "totalApy": apy * vault_boost,
            "poolApy": apy,
            "baseApy": apy,
        }
        return Apy("backscratcher", apy, apy, ApyFees(), composite=composite)
Пример #2
0
    def calculate_apy(self, gauge, lp_token, block=None):
        crv_price = magic.get_price(self.crv)
        pool = contract(self.get_pool(lp_token))
        results = fetch_multicall(
            [gauge, "working_supply"],
            [self.gauge_controller, "gauge_relative_weight", gauge],
            [gauge, "inflation_rate"],
            [pool, "get_virtual_price"],
            block=block,
        )
        results = [x / 1e18 for x in results]
        working_supply, relative_weight, inflation_rate, virtual_price = results
        token_price = magic.get_price(lp_token, block=block)
        try:
            rate = (inflation_rate * relative_weight * 86400 * 365 /
                    working_supply * 0.4) / token_price
        except ZeroDivisionError:
            rate = 0

        return {
            "crv price": crv_price,
            "relative weight": relative_weight,
            "inflation rate": inflation_rate,
            "virtual price": virtual_price,
            "crv reward rate": rate,
            "crv apy": rate * crv_price,
            "token price": token_price,
        }
Пример #3
0
def staking(address: str,
            pool_price: int,
            base_asset_price: int,
            block: Optional[int] = None) -> float:
    staking_rewards = contract(address)
    end = staking_rewards.periodFinish(block_identifier=block)

    current_time = time() if block is None else get_block_timestamp(block)
    if end < current_time:
        return 0

    snx_address = staking_rewards.snx(
        block_identifier=block) if hasattr(staking_rewards, "snx") else None
    reward_token = staking_rewards.rewardToken(
        block_identifier=block) if hasattr(staking_rewards,
                                           "rewardToken") else None
    rewards_token = staking_rewards.rewardsToken(
        block_identifier=block) if hasattr(staking_rewards,
                                           "rewardsToken") else None

    token = reward_token or rewards_token or snx_address

    total_supply = staking_rewards.totalSupply(
        block_identifier=block) if hasattr(staking_rewards,
                                           "totalSupply") else 0
    rate = staking_rewards.rewardRate(block_identifier=block) if hasattr(
        staking_rewards, "rewardRate") else 0

    if token and rate:
        # Single reward token
        token_price = get_price(token, block=block)
        return (SECONDS_PER_YEAR * (rate / 1e18) * token_price) / (
            (pool_price / 1e18) * (total_supply / 1e18) * base_asset_price)
    else:
        # Multiple reward tokens
        queue = 0
        apr = 0
        try:
            token = staking_rewards.rewardTokens(queue, block_identifier=block)
        except ValueError:
            token = None
        while token and token != ZERO_ADDRESS:
            try:
                data = staking_rewards.rewardData(token,
                                                  block_identifier=block)
            except ValueError:
                token = None
            rate = data.rewardRate / 1e18 if data else 0
            token_price = get_price(token, block=block) or 0
            apr += SECONDS_PER_YEAR * rate * token_price / (
                (pool_price / 1e18) * (total_supply / 1e18) * token_price)
            queue += 1
            try:
                token = staking_rewards.rewardTokens(queue,
                                                     block_identifier=block)
            except ValueError:
                token = None
        return apr
Пример #4
0
def staking(address: str, pool_price: int, base_asset_price: int) -> float:
    staking_rewards = Contract(address)
    end = staking_rewards.periodFinish()
    if end < time():
        return 0

    snx_address = staking_rewards.snx() if hasattr(staking_rewards,
                                                   "snx") else None
    reward_token = staking_rewards.rewardToken() if hasattr(
        staking_rewards, "rewardToken") else None
    rewards_token = staking_rewards.rewardsToken() if hasattr(
        staking_rewards, "rewardsToken") else None

    token = reward_token or rewards_token or snx_address

    total_supply = staking_rewards.totalSupply() if hasattr(
        staking_rewards, "totalSupply") else 0
    rate = staking_rewards.rewardRate() if hasattr(staking_rewards,
                                                   "rewardRate") else 0

    if token and rate:
        # Single reward token
        token_price = get_price(token)
        return (SECONDS_PER_YEAR * (rate / 1e18) * token_price) / (
            (pool_price / 1e18) * (total_supply / 1e18) * base_asset_price)
    else:
        # Multiple reward tokens
        queue = 0
        apr = 0
        try:
            token = staking_rewards.rewardTokens(queue)
        except ValueError:
            token = None
        while token and token != ZERO_ADDRESS:
            try:
                data = staking_rewards.rewardData(token)
            except ValueError:
                token = None
            rate = data.rewardRate / 1e18 if data else 0
            token_price = get_price(token) or 0
            apr += SECONDS_PER_YEAR * rate * token_price / (
                (pool_price / 1e18) * (total_supply / 1e18) * token_price)
            queue += 1
            try:
                token = staking_rewards.rewardTokens(queue)
            except ValueError:
                token = None
        return apr
Пример #5
0
def multi(address: str,
          pool_price: int,
          base_asset_price: int,
          block: Optional[int] = None) -> float:
    multi_rewards = contract(address)

    total_supply = multi_rewards.totalSupply(
        block_identifier=block) if hasattr(multi_rewards, "totalSupply") else 0

    queue = 0
    apr = 0
    if hasattr(multi_rewards, "rewardsToken"):
        token = multi_rewards.rewardTokens(queue, block_identifier=block)
    else:
        token = None
    while token and token != ZERO_ADDRESS:
        try:
            data = multi_rewards.rewardData(token, block_identifier=block)
        except ValueError:
            token = None
        if data.periodFinish >= time():
            rate = data.rewardRate / 1e18 if data else 0
            token_price = get_price(token, block=block) or 0
            apr += SECONDS_PER_YEAR * rate * token_price / (
                (pool_price / 1e18) * (total_supply / 1e18) * token_price)
        queue += 1
        try:
            token = multi_rewards.rewardTokens(queue, block_identifier=block)
        except ValueError:
            token = None
    return apr
Пример #6
0
    def describe(self, block=None):
        try:
            results = fetch_multicall(*[[self.vault, view]
                                        for view in self._views],
                                      block=block)
            info = dict(zip(self._views, results))
            for name in info:
                if name in VAULT_VIEWS_SCALED:
                    info[name] /= self.scale
            info["strategies"] = {}
        except ValueError as e:
            info = {"strategies": {}}

        for strategy in self.strategies:
            info["strategies"][strategy.unique_name] = strategy.describe(
                block=block)

        info["token price"] = magic.get_price(self.token, block=block)
        if "totalAssets" in info:
            info["tvl"] = info["token price"] * info["totalAssets"]

        info["experimental"] = self.is_experiment
        info["address"] = self.vault
        info["version"] = "v2"

        return info
Пример #7
0
 def appendmore(token_address,
                amount,
                wallet,
                category=False,
                wallet_label=False):
     token = contract(token_address)
     price = magic.get_price(token_address, block)
     if category and not wallet_label:
         return df.append(
             pd.DataFrame({
                 'token_address': [token.address],
                 'name': [token.name()],
                 'symbol': [token.symbol()],
                 'balance': [amount],
                 'category': [category],
                 'wallet': [wallet],
                 'wallet_label': [YEARN_WALLETS[wallet]],
                 'price': [price],
                 'value': [amount * price],
             }))
     if wallet_label and not category:
         return df.append(
             pd.DataFrame({
                 'token_address': [token.address],
                 'name': [token.name()],
                 'symbol': [token.symbol()],
                 'balance': [amount],
                 'category': [CATEGORY_MAPPINGS[token.address]],
                 'wallet': [wallet],
                 'wallet_label': [wallet_label],
                 'price': [price],
                 'value': [amount * price],
             }))
     if wallet_label and category:
         return df.append(
             pd.DataFrame({
                 'token_address': [token.address],
                 'name': [token.name()],
                 'symbol': [token.symbol()],
                 'balance': [amount],
                 'category': [category],
                 'wallet': [wallet],
                 'wallet_label': [wallet_label],
                 'price': [price],
                 'value': [amount * price],
             }))
     return df.append(
         pd.DataFrame({
             'token_address': [token.address],
             'name': [token.name()],
             'symbol': [token.symbol()],
             'balance': [amount],
             'category': [CATEGORY_MAPPINGS[token.address]],
             'wallet': [wallet],
             'wallet_label': [YEARN_WALLETS[wallet]],
             'price': [price],
             'value': [amount * price],
         }))
Пример #8
0
 def tvl(self, block=None):
     total_assets = self.vault.totalAssets(block_identifier=block)
     try:
         price = magic.get_price(self.token, block=None)
     except PriceError:
         price = None
     tvl = total_assets * price / 10**self.vault.decimals(
         block_identifier=block) if price else None
     return Tvl(total_assets, price, tvl)
Пример #9
0
 def describe(self, block=None):
     crv_locked = curve.voting_escrow.balanceOf["address"](
         self.proxy, block_identifier=block) / 1e18
     crv_price = magic.get_price(curve.crv, block=block)
     return {
         'totalSupply': crv_locked,
         'token price': crv_price,
         'tvl': crv_locked * crv_price,
     }
Пример #10
0
 def describe(self, block=None):
     yfi_locked = self.token.balanceOf(self.vault,
                                       block_identifier=block) / 1e18
     yfi_price = magic.get_price(str(self.token), block=block)
     return {
         'totalAssets': yfi_locked,
         'token price': yfi_price,
         'tvl': yfi_locked * yfi_price,
     }
Пример #11
0
    def get_tvl(self, pool, block=None):
        """
        Get total value in Curve pool.
        """
        balances = self.get_balances(pool, block=block)
        if balances is None:
            return None

        return sum(balances[coin] * magic.get_price(coin, block=block)
                   for coin in balances)
Пример #12
0
def test_crypto_pool_eur_usd_assets(pool):
    lp_token = eur_usd_crypto_pool_tokens[pool]
    pool = curve.curve.crypto_swap_registry.get_pool_from_lp_token(lp_token)
    coins = curve.curve.crypto_swap_registry.get_coins(pool)
    non_zero_coins = list(filter(lambda coin: coin != ZERO_ADDRESS, coins))
    underlying_coin_prices = map(lambda coin: get_price(coin), non_zero_coins)
    summed_coin_prices = sum(underlying_coin_prices)

    price = curve.curve.get_price(lp_token)
    # the price of the crypto pool token should be approximately equal to the sum of the
    # underlying coins, provided they are roughly equally balanced in the pool
    assert price == pytest.approx(summed_coin_prices, rel=2e-1)
Пример #13
0
def _get_price(event, vault):
    while True:
        try:
            try:
                return magic.get_price(vault.address, event.block_number)
            except TypeError:  # magic.get_price fails because all liquidity was removed for testing and `share_price` returns None
                return magic.get_price(vault.token(), event.block_number)
        except ConnectionError as e:
            # Try again
            print(f'ConnectionError: {str(e)}')
            time.sleep(1)
        except ValueError as e:
            print(f'ValueError: {str(e)}')
            if str(e) in [
                    "Failed to retrieve data from API: {'status': '0', 'message': 'NOTOK', 'result': 'Max rate limit reached'}",
                    "Failed to retrieve data from API: {'status': '0', 'message': 'NOTOK', 'result': 'Max rate limit reached, please use API Key for higher rate limit'}",
            ]:
                # Try again
                print('trying again...')
                time.sleep(5)
            else:
                print(f'vault: {vault.address}')
                raise Exception(str(e))
Пример #14
0
 def unit_collateral(self, block=None) -> dict:
     if block and block < 11315910:
         return
     # ychad = contract('ychad.eth')
     ychad = contract('0xfeb4acf3df3cdea7399794d0869ef76a6efaff52')
     unitVault = contract("0xb1cff81b9305166ff1efc49a129ad2afcd7bcf19")
     yfi = "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e"
     bal = unitVault.collaterals(yfi, ychad, block_identifier=block)
     collateral = {
         yfi: {
             'balance': bal / 10**18,
             'usd value': bal / 10**18 * get_price(yfi, block),
         }
     }
     return collateral
Пример #15
0
def get_price(token, block=None):
    pool = Contract(token)
    tokens, supply = fetch_multicall([pool, "getCurrentTokens"],
                                     [pool, "totalSupply"],
                                     block=block)
    supply = supply / 1e18
    balances = fetch_multicall(*[[pool, "getBalance", token]
                                 for token in tokens],
                               block=block)
    balances = [
        balance / 10**Contract(token).decimals()
        for balance, token in zip(balances, tokens)
    ]
    total = sum(balance * magic.get_price(token, block=block)
                for balance, token in zip(balances, tokens))
    return total / supply
Пример #16
0
    def get_price(self, token, block=None):
        pool = self.get_pool(token)

        # crypto pools can have different tokens, use slow method
        if hasattr(contract(pool), 'price_oracle'):
            tvl = self.get_tvl(pool, block=block)
            if tvl is None:
                return None
            supply = contract(token).totalSupply(block_identifier=block) / 1e18
            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]

        virtual_price = contract(pool).get_virtual_price(block_identifier=block) / 1e18
        return virtual_price * magic.get_price(coin, block)
Пример #17
0
 def maker_collateral(self, block=None) -> dict:
     proxy_registry = contract('0x4678f0a6958e4D2Bc4F1BAF7Bc52E8F3564f3fE4')
     cdp_manager = contract('0x5ef30b9986345249bc32d8928B7ee64DE9435E39')
     # ychad = contract('ychad.eth')
     ychad = contract('0xfeb4acf3df3cdea7399794d0869ef76a6efaff52')
     vat = contract('0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B')
     proxy = proxy_registry.proxies(ychad)
     cdp = cdp_manager.first(proxy)
     urn = cdp_manager.urns(cdp)
     ilk = encode_single('bytes32', b'YFI-A')
     ink = vat.urns(ilk, urn, block_identifier=block).dict()["ink"]
     yfi = "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e"
     collateral = {
         yfi: {
             'balance':
             ink / 10**18,
             'usd value':
             ink / 10**18 * get_price(yfi, block) if ink > 0 else 0,
         }
     }
     return collateral
Пример #18
0
def _get_price(token, block=None):
    SKIP_PRICE = [  # shitcoins
        "0xa9517B2E61a57350D6555665292dBC632C76adFe",
        "0xb07de4b2989E180F8907B8C7e617637C26cE2776",
        "0x1368452Bfb5Cd127971C8DE22C58fBE89D35A6BF",
        "0x5cB5e2d7Ab9Fd32021dF8F1D3E5269bD437Ec3Bf",
        "0x11068577AE36897fFaB0024F010247B9129459E6",
        "0x9694EED198C1b7aB81ADdaf36255Ea58acf13Fab",
        "0x830Cbe766EE470B67F77ea62a56246863F75f376",
        "0x8F49cB69ee13974D6396FC26B0c0D78044FCb3A7",
        "0x53d345839E7dF5a6c8Cf590C5c703AE255E44816",
        "0xcdBb37f84bf94492b44e26d1F990285401e5423e",
        "0xE256CF1C7caEff4383DabafEe6Dd53910F97213D",
        "0x528Ff33Bf5bf96B5392c10bc4748d9E9Fb5386B2",
    ]
    if token in SKIP_PRICE:
        return 0

    try:
        price = get_price(token, block)
    except AttributeError:
        logger.warn(
            f"AttributeError while getting price for {contract(token).symbol()} {token}"
        )
        raise
    except PriceError:
        logger.warn(
            f"PriceError while getting price for {contract(token).symbol()} {token}"
        )
        price = 0
    except ValueError:
        logger.warn(
            f"ValueError while getting price for {contract(token).symbol()} {token}"
        )
        price = 0
    return price
Пример #19
0
    def held_assets(self, block=None) -> dict:
        balances = {}
        for address in self.addresses:
            # get token balances
            tokens = self.token_list(address, block=block)
            token_balances = fetch_multicall(
                *[[contract(token), "balanceOf", address] for token in tokens],
                block=block,
            )
            decimals = fetch_multicall(*[[contract(token), "decimals"]
                                         for token in tokens],
                                       block=block)
            token_balances = [
                balance / 10**decimal if decimal else 0
                for balance, decimal in zip(token_balances, decimals)
            ]
            token_prices = Parallel(8, 'threading')(
                delayed(_get_price)(token, block) for token in tokens)
            token_balances = [{
                'balance': balance,
                'usd value': balance * price
            } for balance, price in zip(token_balances, token_prices)]
            balances[address] = dict(zip(tokens, token_balances))

            # then, add eth
            if block:
                balance = (
                    web3.eth.get_balance(address, block_identifier=block) /
                    10**18)
            else:
                balance = web3.eth.get_balance(address) / 10**18
            balances[address]['ETH'] = {
                'balance': balance,
                'usd value': balance * get_price(weth, block),
            }
        return balances
Пример #20
0
 def total_value_at(self, block=None):
     yfi_locked = self.token.balanceOf(self.vault, block_identifier=block) / 1e18
     yfi_price = magic.get_price(str(self.token), block=block)
     return yfi_locked * yfi_price
Пример #21
0
def simple(vault, samples: ApySamples) -> Apy:
    lp_token = vault.token.address

    pool_address = curve.get_pool(lp_token)

    gauge_address = curve.get_gauge(pool_address)

    if gauge_address is None:
        raise ApyError("crv", "no gauge")

    gauge = contract(gauge_address)

    try:
        controller = gauge.controller()
        controller = contract(controller)
    except:
        # newer gauges do not have a 'controller' method
        controller = curve.gauge_controller

    block = samples.now
    gauge_weight = controller.gauge_relative_weight.call(
        gauge_address, block_identifier=block)
    gauge_working_supply = gauge.working_supply(block_identifier=block)
    if gauge_working_supply == 0:
        raise ApyError("crv", "gauge working supply is zero")

    gauge_inflation_rate = gauge.inflation_rate(block_identifier=block)
    pool = contract(pool_address)
    pool_price = pool.get_virtual_price(block_identifier=block)

    base_asset_price = get_price(lp_token, block=block) or 1

    crv_price = get_price(curve.crv, block=block)

    yearn_voter = addresses[chain.id]['yearn_voter_proxy']
    y_working_balance = gauge.working_balances(yearn_voter,
                                               block_identifier=block)
    y_gauge_balance = gauge.balanceOf(yearn_voter, block_identifier=block)

    base_apr = (gauge_inflation_rate * gauge_weight *
                (SECONDS_PER_YEAR / gauge_working_supply) *
                (PER_MAX_BOOST / pool_price) * crv_price) / base_asset_price

    if y_gauge_balance > 0:
        boost = y_working_balance / (PER_MAX_BOOST * y_gauge_balance) or 1
    else:
        boost = MAX_BOOST

    # FIXME: The HBTC v1 vault is currently still earning yield, but it is no longer boosted.
    if vault.vault.address == "0x46AFc2dfBd1ea0c0760CAD8262A5838e803A37e5":
        boost = 1

    # TODO: come up with cleaner way to deal with these new gauge rewards
    reward_apr = 0
    if hasattr(gauge, "reward_contract"):
        reward_address = gauge.reward_contract()
        if reward_address != ZERO_ADDRESS:
            reward_apr = rewards(reward_address,
                                 pool_price,
                                 base_asset_price,
                                 block=block)
    elif hasattr(gauge, "reward_data"
                 ):  # this is how new gauges, starting with MIM, show rewards
        # get our token
        # TODO: consider adding for loop with [gauge.reward_tokens(i) for i in range(gauge.reward_count())] for multiple rewards tokens
        gauge_reward_token = gauge.reward_tokens(0)
        if gauge_reward_token in [ZERO_ADDRESS]:
            print("no reward token")
        else:
            reward_data = gauge.reward_data(gauge_reward_token)
            rate = reward_data['rate']
            period_finish = reward_data['period_finish']
            total_supply = gauge.totalSupply()
            token_price = 0
            if gauge_reward_token == addresses[chain.id]['rkp3r_rewards']:
                rKP3R_contract = interface.rKP3R(gauge_reward_token)
                discount = rKP3R_contract.discount(block_identifier=block)
                token_price = get_price(addresses[chain.id]['kp3r'],
                                        block=block) * (100 - discount) / 100
            else:
                token_price = get_price(gauge_reward_token, block=block)
            current_time = time() if block is None else get_block_timestamp(
                block)
            if period_finish < current_time:
                reward_apr = 0
            else:
                reward_apr = (SECONDS_PER_YEAR *
                              (rate / 1e18) * token_price) / (
                                  (pool_price / 1e18) *
                                  (total_supply / 1e18) * base_asset_price)
    else:
        reward_apr = 0

    price_per_share = pool.get_virtual_price
    now_price = price_per_share(block_identifier=samples.now)
    try:
        week_ago_price = price_per_share(block_identifier=samples.week_ago)
    except ValueError:
        raise ApyError("crv", "insufficient data")

    now_point = SharePricePoint(samples.now, now_price)
    week_ago_point = SharePricePoint(samples.week_ago, week_ago_price)

    pool_apr = calculate_roi(now_point, week_ago_point)
    pool_apy = (((pool_apr / 365) + 1)**365) - 1

    # FIXME: crvANKR's pool apy going crazy
    if vault.vault.address == "0xE625F5923303f1CE7A43ACFEFd11fd12f30DbcA4":
        pool_apy = 0

    # prevent circular import for partners calculations
    from yearn.v2.vaults import Vault as VaultV2

    if isinstance(vault, VaultV2):
        vault_contract = vault.vault
        if len(vault.strategies) > 0 and hasattr(vault.strategies[0].strategy,
                                                 "keepCRV"):
            crv_keep_crv = vault.strategies[0].strategy.keepCRV(
                block_identifier=block) / 1e4
        elif len(vault.strategies) > 0 and hasattr(
                vault.strategies[0].strategy, "keepCrvPercent"):
            crv_keep_crv = vault.strategies[0].strategy.keepCrvPercent(
                block_identifier=block) / 1e4
        else:
            crv_keep_crv = 0
        performance = (vault_contract.performanceFee(block_identifier=block) *
                       2) / 1e4 if hasattr(vault_contract,
                                           "performanceFee") else 0
        management = vault_contract.managementFee(
            block_identifier=block) / 1e4 if hasattr(vault_contract,
                                                     "managementFee") else 0
    else:
        strategy = vault.strategy
        strategist_performance = strategy.performanceFee(
            block_identifier=block) if hasattr(strategy,
                                               "performanceFee") else 0
        strategist_reward = strategy.strategistReward(
            block_identifier=block) if hasattr(strategy,
                                               "strategistReward") else 0
        treasury = strategy.treasuryFee(
            block_identifier=block) if hasattr(strategy, "treasuryFee") else 0
        crv_keep_crv = strategy.keepCRV(
            block_identifier=block) / 1e4 if hasattr(strategy,
                                                     "keepCRV") else 0

        performance = (strategist_reward + strategist_performance +
                       treasury) / 1e4
        management = 0

    if isinstance(vault, VaultV2) and len(vault.strategies) == 2:
        crv_strategy = vault.strategies[0].strategy
        cvx_strategy = vault.strategies[1].strategy
        convex_voter = addresses[chain.id]['convex_voter_proxy']
        cvx_working_balance = gauge.working_balances(convex_voter,
                                                     block_identifier=block)
        cvx_gauge_balance = gauge.balanceOf(convex_voter,
                                            block_identifier=block)

        if cvx_gauge_balance > 0:
            cvx_boost = cvx_working_balance / (PER_MAX_BOOST *
                                               cvx_gauge_balance) or 1
        else:
            cvx_boost = MAX_BOOST

        cvx_booster = contract(addresses[chain.id]['convex_booster'])
        cvx_lock_incentive = cvx_booster.lockIncentive(block_identifier=block)
        cvx_staker_incentive = cvx_booster.stakerIncentive(
            block_identifier=block)
        cvx_earmark_incentive = cvx_booster.earmarkIncentive(
            block_identifier=block)
        cvx_fee = (cvx_lock_incentive + cvx_staker_incentive +
                   cvx_earmark_incentive) / 1e4
        cvx_keep_crv = cvx_strategy.keepCRV(block_identifier=block) / 1e4

        total_cliff = 1e3
        max_supply = 1e2 * 1e6 * 1e18  # ?
        reduction_per_cliff = 1e23
        cvx = contract(addresses[chain.id]['cvx'])
        supply = cvx.totalSupply(block_identifier=block)
        cliff = supply / reduction_per_cliff
        if supply <= max_supply:
            reduction = total_cliff - cliff
            cvx_minted_as_crv = reduction / total_cliff
            cvx_price = get_price(cvx, block=block)
            converted_cvx = cvx_price / crv_price
            cvx_printed_as_crv = cvx_minted_as_crv * converted_cvx
        else:
            cvx_printed_as_crv = 0

        cvx_apr = ((1 - cvx_fee) * cvx_boost *
                   base_apr) * (1 + cvx_printed_as_crv) + reward_apr
        cvx_apr_minus_keep_crv = ((1 - cvx_fee) * cvx_boost * base_apr) * (
            (1 - cvx_keep_crv) + cvx_printed_as_crv)

        crv_debt_ratio = vault.vault.strategies(crv_strategy)[2] / 1e4
        cvx_debt_ratio = vault.vault.strategies(cvx_strategy)[2] / 1e4
    else:
        cvx_apr = 0
        cvx_apr_minus_keep_crv = 0
        cvx_keep_crv = 0
        crv_debt_ratio = 1
        cvx_debt_ratio = 0

    crv_apr = base_apr * boost + reward_apr
    crv_apr_minus_keep_crv = base_apr * boost * (1 - crv_keep_crv)

    gross_apr = (1 + (crv_apr * crv_debt_ratio + cvx_apr * cvx_debt_ratio)) * (
        1 + pool_apy) - 1

    cvx_net_apr = (cvx_apr_minus_keep_crv +
                   reward_apr) * (1 - performance) - management
    cvx_net_farmed_apy = (1 + (cvx_net_apr / COMPOUNDING))**COMPOUNDING - 1
    cvx_net_apy = ((1 + cvx_net_farmed_apy) * (1 + pool_apy)) - 1

    crv_net_apr = (crv_apr_minus_keep_crv +
                   reward_apr) * (1 - performance) - management
    crv_net_farmed_apy = (1 + (crv_net_apr / COMPOUNDING))**COMPOUNDING - 1
    crv_net_apy = ((1 + crv_net_farmed_apy) * (1 + pool_apy)) - 1

    net_apy = crv_net_apy * crv_debt_ratio + cvx_net_apy * cvx_debt_ratio

    # 0.3.5+ should never be < 0% because of management
    if isinstance(vault, VaultV2) and net_apy < 0 and Version(
            vault.api_version) >= Version("0.3.5"):
        net_apy = 0

    fees = ApyFees(performance=performance,
                   management=management,
                   keep_crv=crv_keep_crv,
                   cvx_keep_crv=cvx_keep_crv)
    composite = {
        "boost": boost,
        "pool_apy": pool_apy,
        "boosted_apr": crv_apr,
        "base_apr": base_apr,
        "cvx_apr": cvx_apr,
        "rewards_apr": reward_apr,
    }

    return Apy("crv", gross_apr, net_apy, fees, composite=composite)
Пример #22
0
def test_uniswap_v3(token):
    price = v3.uniswap_v3.get_price(token)
    alt_price = magic.get_price(token)
    print(token, price, alt_price)
    assert price == pytest.approx(alt_price, rel=5e-2)
Пример #23
0
def test_uniswap_v1(token):
    price = v1.uniswap_v1.get_price(token)
    alt_price = magic.get_price(token)
    print(token, price, alt_price)
    # check if price is within 5% range
    assert price == pytest.approx(alt_price, rel=5e-2)
Пример #24
0
 def getprice(token_address):
     if token_address == '0x27d22a7648e955e510a40bdb058333e9190d12d4':  # PPOOL
         return magic.get_price(
             '0x0cec1a9154ff802e7934fc916ed7ca50bde6844e', block)
     return magic.get_price(token_address, block)
Пример #25
0
 def total_value_at(self, block=None):
     crv_locked = voting_escrow.balanceOf["address"](self.proxy, block_identifier=block) / 1e18
     crv_price = magic.get_price(crv, block=block)
     return crv_locked * crv_price
Пример #26
0
def walletdataframe(wallet, block):
    # NOTE: Moralis API is returning absurd values for token balances,
    # so we will disreagrd balances returned by the API. We only use
    # the API to fetch a list of tokens in the wallet. We then use the
    # token list to query correct balances from the blockchain.

    url = f'{moralis}{wallet}/erc20'
    df = pd.DataFrame(get(url, headers=headers).json())

    # NOTE: Remove spam tokens
    df = df[~df.token_address.isin(SPAM_TOKENS)]

    def getcategory(token_address):
        try:
            return CATEGORY_MAPPINGS[token_address]
        except KeyError:
            return

    def getbalance(token_address):
        logging.debug(f'token: {token_address}')
        return contract(token_address).balanceOf(wallet,
                                                 block_identifier=block)

    def getprice(token_address):
        if token_address == '0x27d22a7648e955e510a40bdb058333e9190d12d4':  # PPOOL
            return magic.get_price(
                '0x0cec1a9154ff802e7934fc916ed7ca50bde6844e', block)
        return magic.get_price(token_address, block)

    # NOTE: Add some details
    df['wallet'] = wallet
    df['wallet_label'] = YEARN_WALLETS[wallet]
    df['category'] = df['token_address'].apply(getcategory)

    # NOTE: Do some maths
    df['balance'] = df['token_address'].apply(
        getbalance) / 10**df['decimals'].apply(int)
    df['price'] = df['token_address'].apply(getprice)
    df['value'] = df['balance'] * df['price']

    # NOTE: Get rid of columns we don't need
    df = df.drop(columns=['logo', 'thumbnail', 'decimals'])

    # NOTE: Get rid of tokens with 0 balance
    df = df[df['balance'] != 0]

    ethbal = web3.eth.get_balance(convert.to_address(wallet),
                                  block_identifier=block) / 10**18
    if ethbal > 0:
        ethprice = magic.get_price(
            '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', block)
        return df.append(
            pd.DataFrame({
                'token_address': [None],
                'name': ['Ethereum'],
                'symbol': ['ETH'],
                'balance': [ethbal],
                'category': ['ETH'],
                'wallet': [wallet],
                'wallet_label': [YEARN_WALLETS[wallet]],
                'price': [ethprice],
                'value': [ethbal * ethprice],
            }))
    return df
Пример #27
0
 def get_price(self, block=None):
     if self.name == "aLINK":
         return magic.get_price(self.vault.underlying(), block=block)
     return magic.get_price(self.token, block=block)
Пример #28
0
def simple(vault: Union[VaultV1, VaultV2], samples: ApySamples) -> Apy:
    lp_token = vault.token.address

    pool_address = get_pool(lp_token)
    gauge_addresses = curve_registry.get_gauges(pool_address)

    gauge_address = gauge_addresses[0][0]

    # FIXME: crvUSDP doesn't have a gauge connected in the registry
    if vault.vault.address == "0x1B5eb1173D2Bf770e50F10410C9a96F7a8eB6e75":
        gauge = "0x055be5DDB7A925BfEF3417FC157f53CA77cA7222"

    gauge = interface.CurveGauge(gauge_address)
    controller = gauge.controller()
    controller = interface.CurveGaugeController(controller)

    gauge_working_supply = gauge.working_supply()
    gauge_weight = controller.gauge_relative_weight(gauge_address)

    gauge_inflation_rate = gauge.inflation_rate()
    pool_price = curve_registry.get_virtual_price_from_lp_token(lp_token)

    underlying_coins = get_underlying_coins(lp_token)

    btc_like = any([coin in BTC_LIKE for coin in underlying_coins])
    eth_like = any([coin in ETH_LIKE for coin in underlying_coins])

    base_asset = WBTC if btc_like else WETH if eth_like else underlying_coins[0]
    base_asset_price = get_price(base_asset) or 1

    crv_price = get_price(CRV)

    y_working_balance = gauge.working_balances(YVECRV_VOTER)
    y_gauge_balance = gauge.balanceOf(YVECRV_VOTER)

    base_apr = (
        gauge_inflation_rate
        * gauge_weight
        * (SECONDS_PER_YEAR / gauge_working_supply)
        * (PER_MAX_BOOST / pool_price)
        * crv_price
    ) / base_asset_price

    if y_gauge_balance > 0:
        boost = y_working_balance / (PER_MAX_BOOST * y_gauge_balance) or 1
    else:
        boost = MAX_BOOST

    # FIXME: The HBTC v1 vault is currently still earning yield, but it is no longer boosted.
    if vault.vault.address == "0x46AFc2dfBd1ea0c0760CAD8262A5838e803A37e5":
        boost = 1

    boosted_apr = base_apr * boost

    if hasattr(gauge, "reward_contract"):
        try:
            reward_address = gauge.reward_contract()
            assert reward_address != ZERO_ADDRESS
            reward_apr = rewards(reward_address, pool_price, base_asset_price)
        except ValueError:
            reward_apr = 0
    else:
        reward_apr = 0

    price_per_share = curve_registry.get_virtual_price_from_lp_token
    now_price = price_per_share(lp_token, block_identifier=samples.now)
    try:
        week_ago_price = price_per_share(lp_token, block_identifier=samples.week_ago)
    except ValueError:
        raise ApyError("crv", "insufficient data")

    now_point = SharePricePoint(samples.now, now_price)
    week_ago_point = SharePricePoint(samples.week_ago, week_ago_price)

    pool_apr = calculate_roi(now_point, week_ago_point)
    pool_apy = (((pool_apr / 365) + 1) ** 365) - 1

    # FIXME: crvANKR's pool apy going crazy
    if vault.vault.address == "0xE625F5923303f1CE7A43ACFEFd11fd12f30DbcA4":
        pool_apy = 0

    if type(vault) is VaultV2:
        contract = vault.vault
        keep_crv = sum([strategy.keepCRV() for strategy in vault.strategies if hasattr(strategy, "keepCRV")])
        performance = (contract.performanceFee() * 2) if hasattr(contract, "performanceFee") else 0
        management = contract.managementFee() if hasattr(contract, "managementFee") else 0
    else:
        strategy = vault.strategy
        strategist_performance = strategy.performanceFee() if hasattr(strategy, "performanceFee") else 0
        strategist_reward = strategy.strategistReward() if hasattr(strategy, "strategistReward") else 0
        treasury = strategy.treasuryFee() if hasattr(strategy, "treasuryFee") else 0
        keep_crv = strategy.keepCRV() if hasattr(strategy, "keepCRV") else 0

        performance = strategist_reward + strategist_performance + treasury
        management = 0

    keep_crv /= 1e4
    performance /= 1e4
    management /= 1e4

    lose_crv = 1 - keep_crv

    gross_farmed_apy = (
        (boosted_apr * keep_crv) + (((boosted_apr * lose_crv + reward_apr) / COMPOUNDING) + 1) ** COMPOUNDING
    ) - 1

    apy = (gross_farmed_apy + 1) * (pool_apy + 1) - 1

    net_curve_apr = (boosted_apr * lose_crv + reward_apr) * (1 - performance) - management

    net_farmed_apy = ((net_curve_apr / COMPOUNDING) + 1) ** COMPOUNDING - 1
    net_apy = (net_farmed_apy + 1) * (pool_apy + 1) - 1

    fees = ApyFees(performance=performance, management=management, keep_crv=keep_crv)
    composite = {
        "boost": boost,
        "pool_apy": pool_apy,
        "boosted_apr": boosted_apr,
        "base_apr": base_apr,
        "rewards_apr": reward_apr,
    }
    return Apy("crv", apy, net_apy, fees, composite=composite)
Пример #29
0
 def get_price(self, vault: Union[VaultV1, VaultV2], block=None):
     if isinstance(vault, VaultV1) and vault.name == "aLINK":
         return magic.get_price(self.vault.underlying(), block=block)
     else:
         return magic.get_price(self.token, block=block)