def describe(self): scale = 10**self.decimals info = { "vault balance": self.vault.balance() / scale, "share price": self.vault.getPricePerFullShare() / 1e18, "vault total": self.vault.totalSupply() / scale, "strategy balance": self.strategy.balanceOf() / scale, } # some of the oldest vaults don't implement these methods if hasattr(self.vault, "available"): info["available"] = self.vault.available() / scale if hasattr(self.vault, "min") and hasattr(self.vault, "max"): info["strategy buffer"] = self.vault.min() / self.vault.max() # new curve voter proxy vaults if hasattr(self.strategy, "proxy"): vote_proxy = interface.CurveYCRVVoter(self.strategy.voter()) # curve swap is broken across several strategies swap = interface.CurveSwap( constants.CURVE_SWAP_OVERRIDES.get(self.strategy._name, self.strategy.curve())) gauge = interface.CurveGauge(self.strategy.gauge()) info.update(curve.calculate_boost(gauge, vote_proxy)) info.update(curve.calculate_apy(gauge, swap)) info["earned"] = gauge.claimable_tokens.call(vote_proxy).to( "ether") if hasattr(self.strategy, "earned"): info["lifetime earned"] = self.strategy.earned() / scale if self.strategy._name == "StrategyYFIGovernance": ygov = interface.YearnGovernance(self.strategy.gov()) info["earned"] = ygov.earned(self.strategy) / 1e18 info["reward rate"] = ygov.rewardRate() / 1e18 info["ygov balance"] = ygov.balanceOf(self.strategy) / 1e18 info["ygov total"] = ygov.totalSupply() / 1e18 if "token price" not in info: if self.name in ["aLINK"]: info["token price"] = uniswap.token_price( self.vault.underlying()) elif self.name in ["USDC", "TUSD", "DAI", "USDT"]: info["token price"] = 1 else: info["token price"] = uniswap.token_price(self.token) info["tvl"] = info["vault balance"] * info["token price"] return info
def describe(self): scale = 10**self.vault.decimals() strats = [str(strat.strategy) for strat in self.strategies] strats.extend([ZERO_ADDRESS] * (40 - len(strats))) try: info = { "totalAssets": self.vault.totalAssets() / scale, "maxAvailableShares": self.vault.maxAvailableShares() / scale, "pricePerShare": self.vault.pricePerShare() / scale, "debtOutstanding": self.vault.debtOutstanding() / scale, "creditAvailable": self.vault.creditAvailable() / scale, "expectedReturn": self.vault.expectedReturn() / scale, "totalSupply": self.vault.totalSupply() / scale, "emergencyShutdown": self.vault.emergencyShutdown(), "depositLimit": self.vault.depositLimit() / scale, "debtRatio": self.vault.debtRatio(), "totalDebt": self.vault.totalDebt() / scale, "lastReport": self.vault.lastReport(), "managementFee": self.vault.managementFee(), "performanceFee": self.vault.performanceFee(), "strategies": {}, } except ValueError as e: info = {"strategies": {}} for strat in self.strategies: info["strategies"][strat.name] = strat.describe() info["token price"] = uniswap.token_price(self.vault.token()) if "totalAssets" in info: info["tvl"] = info["token price"] * info["totalAssets"] return info
def describe_ironbank(markets): blocks_per_year = 365 * 86400 / 15 contracts = [m.ctoken for m in markets] results = multicall_matrix( contracts, [ "exchangeRateCurrent", "getCash", "totalBorrows", "totalSupply", "totalReserves", "supplyRatePerBlock", "borrowRatePerBlock", ], ) output = defaultdict(dict) for m in markets: res = results[m.ctoken] price = uniswap.token_price(m.underlying) exchange_rate = res["exchangeRateCurrent"] * 10 ** (m.cdecimals - m.decimals - 18) for attr in ["getCash", "totalBorrows", "totalReserves"]: res[attr] /= 10 ** m.decimals tvl = (res["getCash"] + res["totalBorrows"] - res["totalReserves"]) * price supplied = res["getCash"] + res["totalBorrows"] - res["totalReserves"] ratio = res["totalBorrows"] / supplied if supplied != 0 else None output[m.name] = { "total supply": res["totalSupply"] / 10 ** m.cdecimals, "total cash": res["getCash"], "total supplied": supplied, "total borrows": res["totalBorrows"], "total reserves": res["totalReserves"], "exchange rate": exchange_rate, "token price": price * exchange_rate, "underlying price": price, "supply apy": res["supplyRatePerBlock"] / 1e18 * blocks_per_year, "borrow apy": res["borrowRatePerBlock"] / 1e18 * blocks_per_year, "utilization": ratio, "tvl": tvl, } return dict(output)
def describe_iearn(iearn: List[iEarn]) -> dict: contracts = [x.contract for x in iearn] results = multicall_matrix( contracts, ["totalSupply", "pool", "getPricePerFullShare", "balance"]) output = defaultdict(dict) for i in iearn: res = results[i.contract] price = token_price(i.token) output[i.name] = { "total supply": res["totalSupply"] / 10**i.decimals, "available balance": res["balance"] / 10**i.decimals, "pooled balance": res["pool"] / 10**i.decimals, "price per share": res["getPricePerFullShare"] / 1e18, "token price": price, "tvl": res["pool"] / 10**i.decimals * price, } return dict(output)
def get_base_price(pool_or_lp): # try to find pool for lp, otherwise assume pool pool = lp_to_pool(pool_or_lp) if pool == ZERO_ADDRESS: pool = pool_or_lp return uniswap.token_price(get_underlying(pool)[0])
def describe(self): scale = 10**self.decimals info = {} try: info['share price'] = self.vault.getPricePerFullShare() / 1e18 except ValueError: # no money in vault, exit early return {'tvl': 0} attrs = { 'vault balance': [self.vault, 'balance'], 'vault total': [self.vault, 'totalSupply'], 'strategy balance': [self.strategy, 'balanceOf'], } # some of the oldest vaults don't implement these methods if hasattr(self.vault, "available"): attrs['available'] = [self.vault, 'available'] if hasattr(self.vault, "min") and hasattr(self.vault, "max"): attrs['min'] = [self.vault, 'min'] attrs['max'] = [self.vault, 'max'] # new curve voter proxy vaults if hasattr(self.strategy, "proxy"): results = fetch_multicall( [self.strategy, 'voter'], [curve.registry, 'get_pool_from_lp_token', self.token], [self.strategy, 'gauge'], ) vote_proxy = interface.CurveYCRVVoter(results[0]) swap = interface.CurveSwap(results[1]) gauge = interface.CurveGauge(results[2]) info.update(curve.calculate_boost(gauge, vote_proxy)) info.update(curve.calculate_apy(gauge, swap)) info["earned"] = gauge.claimable_tokens.call(vote_proxy).to( "ether") if hasattr(self.strategy, "earned"): info["lifetime earned"] = self.strategy.earned() / scale if self.strategy._name == "StrategyYFIGovernance": ygov = interface.YearnGovernance(self.strategy.gov()) attrs["earned"] = [ygov, 'earned', self.strategy] attrs["reward rate"] = [ygov, 'rewardRate'] attrs["ygov balance"] = [ygov, 'balanceOf', self.strategy] attrs["ygov total"] = [ygov, 'totalSupply'] # fetch attrs as multicall try: results = fetch_multicall(*attrs.values()) except ValueError: pass else: for name, attr in zip(attrs, results): info[name] = attr / scale # some additional post-processing if 'min' in info: info["strategy buffer"] = info.pop('min') / info.pop('max') if "token price" not in info: if self.name in ["aLINK"]: info["token price"] = uniswap.token_price( self.vault.underlying()) elif self.name in ["USDC", "TUSD", "DAI", "USDT"]: info["token price"] = 1 else: info["token price"] = uniswap.token_price(self.token) info["tvl"] = info["vault balance"] * info["token price"] return info