def active_vaults_at(self, block=None): if block is None: return self.vaults return [ market for market in self.vaults if contract_creation_block(str(market.vault)) < block ]
def test_curve_lp_price_oracle_historical(name): if name in ['linkusd']: pytest.xfail('no active market') token = web3.toChecksumAddress(pooldata[name]['lp_token_address']) swap = web3.toChecksumAddress(pooldata[name]['swap_address']) deploy = contract_creation_block(swap) # sample 10 blocks over the pool lifetime blocks = [ int(block) for block in np.linspace(deploy + 10000, chain.height, 10) ] prices = [] for block in blocks: try: prices.append(curve.curve.get_price(token, block)) except (PriceError, TypeError): prices.append(None) virtual_prices = [ contract(swap).get_virtual_price(block_identifier=block) / 1e18 for block in blocks ] print( tabulate(list(zip(blocks, prices, virtual_prices)), headers=['block', 'price', 'vp']))
def active_vaults_at_block(self, block=None): if block is None: return self.vaults return [ vault for vault in self.vaults if contract_creation_block(str(vault.vault)) < block ]
def get_price(self, token, block=None): if block and block < contract_creation_block(UNISWAP_V3_QUOTER): return None if token == usdc: return 1 paths = [] if token != weth: paths += [[token, fee, weth, self.fee_tiers[0], usdc] for fee in self.fee_tiers] paths += [[token, fee, usdc] for fee in self.fee_tiers] scale = 10**contract(token).decimals() results = fetch_multicall( *[[self.quoter, 'quoteExactInput', self.encode_path(path), scale] for path in paths], block=block, ) outputs = [ amount / self.undo_fees(path) / 1e6 for amount, path in zip(results, paths) if amount ] return max(outputs) if outputs else None
def __init__(self): if chain.id not in addresses: raise UnsupportedNetwork("fixed forex is not supported on this network") self.registry = contract(addresses[chain.id]) self.registry_deploy_block = contract_creation_block(addresses[chain.id]) self.markets = self.registry.forex() logger.info(f'loaded {len(self.markets)} fixed forex markets')
def active_vaults_at(self, block=None): vaults = list(self.vaults) if block: vaults = [ vault for vault in vaults if contract_creation_block(str(vault.vault)) < block ] return vaults
def simple(vault: VaultV1, samples: ApySamples) -> Apy: inception_block = contract_creation_block(vault.vault.address) if not inception_block: raise ApyError("v1:blocks", "inception_block not found") contract = vault.vault price_per_share = contract.getPricePerFullShare inception_price = 1e18 try: now_price = price_per_share(block_identifier=samples.now) except ValueError: now_price = inception_price if samples.week_ago > inception_block: try: week_ago_price = price_per_share(block_identifier=samples.week_ago) except ValueError: week_ago_price = now_price else: week_ago_price = now_price if samples.month_ago > inception_block: try: month_ago_price = price_per_share(block_identifier=samples.month_ago) except ValueError: month_ago_price = week_ago_price else: month_ago_price = week_ago_price now_point = SharePricePoint(samples.now, now_price) week_ago_point = SharePricePoint(samples.week_ago, week_ago_price) month_ago_point = SharePricePoint(samples.month_ago, month_ago_price) inception_point = SharePricePoint(inception_block, inception_price) week_ago_apy = calculate_roi(now_point, week_ago_point) month_ago_apy = calculate_roi(now_point, month_ago_point) inception_apy = calculate_roi(now_point, inception_point) net_apy = month_ago_apy strategy = vault.strategy withdrawal = strategy.withdrawalFee() if hasattr(strategy, "withdrawalFee") else 0 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 performance = strategist_reward + strategist_performance + treasury apy = net_apy / (1 - performance / 1e4) points = ApyPoints(week_ago_apy, month_ago_apy, inception_apy) fees = ApyFees(performance=performance, withdrawal=withdrawal) return Apy("v1:simple", apy, net_apy, fees, points=points)
def create_filter(address, topics=None): """ Create a log filter for one or more contracts. Set fromBlock as the earliest creation block. """ if isinstance(address, list): start_block = min(map(contract_creation_block, address)) else: start_block = contract_creation_block(address) return web3.eth.filter({"address": address, "fromBlock": start_block, "topics": topics})
def main(): yearn = Yearn(load_strategies=False) excluded = {"0xBa37B002AbaFDd8E89a1995dA52740bbC013D992"} resp = requests.get( "https://raw.githubusercontent.com/iearn-finance/yearn-assets/master/icons/aliases.json" ).json() aliases = {item["address"]: item for item in resp} tokens = [] for product in yearn.registries: vaults = [ item.vault for item in yearn.registries[product].vaults if str(item.vault) not in excluded ] metadata = multicall_matrix(vaults, ["name", "symbol", "decimals"]) for vault in vaults: tokens.append( TokenInfo( chainId=1, address=str(vault), name=aliases.get(str(vault), metadata[vault])["name"], decimals=metadata[vault]["decimals"], symbol=aliases.get(str(vault), metadata[vault])["symbol"], logoURI= f"https://raw.githubusercontent.com/yearn/yearn-assets/master/icons/tokens/{vault}/logo.svg", tags=[product], )) # remove token = bump major, add token = bump minor version = Version(major=0, minor=len(tokens), patch=0) deploy_blocks = { token.address: contract_creation_block(token.address) for token in tokens } tokens = sorted(tokens, key=lambda token: deploy_blocks[token.address]) timestamp = datetime.fromtimestamp( get_block_timestamp(max(deploy_blocks.values())), timezone.utc).isoformat() logo = "https://raw.githubusercontent.com/yearn/yearn-assets/master/icons/tokens/0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e/logo.svg" print(f"{version=}\n{timestamp=}") tokenlist = TokenList("Yearn", timestamp, version, tokens, logoURI=logo) for token in tokenlist.tokens: assert len(token.symbol ) <= 20, f"{token.symbol} > 20 chars, uniswap is unhappy" path = Path("static/tokenlist.json") path.parent.mkdir(exist_ok=True) path.write_text(json.dumps(tokenlist.to_dict(), separators=(",", ":"))) print(f"saved to {path}")
def active_vaults_at(self, block=None): vaults = self.vaults + self.experiments if block: vaults = [ vault for vault in vaults if contract_creation_block(str(vault.vault)) <= block ] # fixes edge case: a vault is not necessarily initialized on creation activations = fetch_multicall(*[[vault.vault, 'activation'] for vault in vaults], block=block) return [ vault for vault, activation in zip(vaults, activations) if activation ]
def fetch_multicall(*calls, block=None): # https://github.com/makerdao/multicall multicall_input = [] fn_list = [] decoded = [] for contract, fn_name, *fn_inputs in calls: fn = getattr(contract, fn_name) # check that there aren't multiple functions with the same name if hasattr(fn, "_get_fn_from_args"): fn = fn._get_fn_from_args(fn_inputs) fn_list.append(fn) multicall_input.append((contract, fn.encode_input(*fn_inputs))) if isinstance( block, int) and block < contract_creation_block(MULTICALL2[chain.id]): # use state override to resurrect the contract prior to deployment data = multicall2.tryAggregate.encode_input(False, multicall_input) call = web3.eth.call( { 'to': str(multicall2), 'data': data }, block or 'latest', {str(multicall2): { 'code': f'0x{multicall2.bytecode}' }}, ) result = multicall2.tryAggregate.decode_output(call) else: result = multicall2.tryAggregate.call(False, multicall_input, block_identifier=block or 'latest') for fn, (ok, data) in zip(fn_list, result): try: assert ok, "call failed" decoded.append(fn.decode_output(data)) except (AssertionError, InsufficientDataBytes): decoded.append(None) return decoded
def get_logs_asap(address, topics, from_block=None, to_block=None, verbose=0): logs = [] if from_block is None: from_block = contract_creation_block(address) if to_block is None: to_block = chain.height ranges = list(block_ranges(from_block, to_block, BATCH_SIZE[chain.id])) if verbose > 0: logger.info('fetching %d batches', len(ranges)) batches = Parallel(8, "threading", verbose=verbose)( delayed(web3.eth.get_logs)({ "address": address, "topics": topics, "fromBlock": start, "toBlock": end }) for start, end in ranges) for batch in batches: logs.extend(batch) return logs
def wrap_vault( vault: Union[VaultV1, VaultV2], samples: ApySamples, aliases: dict, icon_url: str, assets_metadata: dict ) -> dict: apy_error = Apy("error", 0, 0, ApyFees(0, 0), ApyPoints(0, 0, 0)) try: apy = vault.apy(samples) except ValueError as error: logger.error(error) apy = apy_error except PriceError as error: logger.error(error) apy = apy_error if isinstance(vault, VaultV1): strategies = [ { "address": str(vault.strategy), "name": vault.strategy.getName() if hasattr(vault.strategy, "getName") else vault.strategy._name, } ] else: strategies = [{"address": str(strategy.strategy), "name": strategy.name} for strategy in vault.strategies] inception = contract_creation_block(str(vault.vault)) token_alias = aliases[str(vault.token)]["symbol"] if str(vault.token) in aliases else vault.token.symbol() vault_alias = token_alias tvl = vault.tvl() migration = None if str(vault.vault) in assets_metadata: migration = {"available": assets_metadata[str(vault.vault)][1], "address": assets_metadata[str(vault.vault)][2]} object = { "inception": inception, "address": str(vault.vault), "symbol": vault.symbol if hasattr(vault, "symbol") else vault.vault.symbol(), "name": vault.name, "display_name": vault_alias, "icon": icon_url % str(vault.vault), "token": { "name": vault.token.name() if hasattr(vault.token, "name") else vault.token._name, "symbol": vault.token.symbol() if hasattr(vault.token, "symbol") else None, "address": str(vault.token), "decimals": vault.token.decimals() if hasattr(vault.token, "decimals") else None, "display_name": token_alias, "icon": icon_url % str(vault.token), }, "tvl": dataclasses.asdict(tvl), "apy": dataclasses.asdict(apy), "strategies": strategies, "endorsed": vault.is_endorsed if hasattr(vault, "is_endorsed") else True, "version": vault.api_version if hasattr(vault, "api_version") else "0.1", "decimals": vault.decimals if hasattr(vault, "decimals") else vault.vault.decimals(), "type": "v2" if isinstance(vault, VaultV2) else "v1", "emergency_shutdown": vault.vault.emergencyShutdown() if hasattr(vault.vault, "emergencyShutdown") else False, "updated": int(time()), "migration": migration, } if chain.id == 1 and any([isinstance(vault, t) for t in [Backscratcher, YveCRVJar]]): object["special"] = True return object
def main(): yearn = Yearn(load_strategies=False) excluded = { "0xBa37B002AbaFDd8E89a1995dA52740bbC013D992", "0xe2F6b9773BF3A015E2aA70741Bde1498bdB9425b", "0xBFa4D8AA6d8a379aBFe7793399D3DdaCC5bBECBB", } resp = requests.get( "https://raw.githubusercontent.com/iearn-finance/yearn-assets/master/icons/aliases.json" ).json() aliases = {item["address"]: item for item in resp} tokens = [] # Token derived by products for product in yearn.registries: vaults = [ item.vault for item in yearn.registries[product].vaults if str(item.vault) not in excluded ] metadata = multicall_matrix(vaults, ["name", "symbol", "decimals"]) for vault in vaults: tokens.append( TokenInfo( chainId=1, address=str(vault), name=aliases.get(str(vault), metadata[vault])["name"], decimals=metadata[vault]["decimals"], symbol=aliases.get(str(vault), metadata[vault])["symbol"], logoURI= f"https://raw.githubusercontent.com/yearn/yearn-assets/master/icons/tokens/{vault}/logo.svg", tags=[product], )) # Token from special / side projects special = [ contract("0xD0660cD418a64a1d44E9214ad8e459324D8157f1") # WOOFY ] metadata = multicall_matrix(special, ["name", "symbol", "decimals"]) for token in special: tokens.append( TokenInfo( chainId=1, address=str(token), name=aliases.get(str(token), metadata[token])["name"], decimals=metadata[token]["decimals"], symbol=aliases.get(str(token), metadata[token])["symbol"], logoURI= f"https://raw.githubusercontent.com/yearn/yearn-assets/master/icons/tokens/{token}/logo.svg", tags=["special"], )) deploy_blocks = { token.address: contract_creation_block(token.address) for token in tokens } tokens = unique(tokens, key=lambda token: token.address) tokens = sorted(tokens, key=lambda token: deploy_blocks[token.address]) version = Version(major=1, minor=len(tokens), patch=0) timestamp = datetime.fromtimestamp( get_block_timestamp(max(deploy_blocks.values())), timezone.utc).isoformat() logo = "https://raw.githubusercontent.com/yearn/yearn-assets/master/icons/tokens/0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e/logo.svg" print(f"{version=}\n{timestamp=}") tokenlist = TokenList("Yearn", timestamp, version, tokens, logoURI=logo) for token in tokenlist.tokens: assert len(token.symbol ) <= 20, f"{token.symbol} > 20 chars, uniswap is unhappy" path = Path("static/tokenlist.json") path.parent.mkdir(exist_ok=True) path.write_text(json.dumps(tokenlist.to_dict(), separators=(",", ":"))) print(f"saved to {path}")
def simple(vault, samples: ApySamples) -> Apy: inception_block = contract_creation_block(vault.vault.address) if not inception_block: raise ApyError("v1:blocks", "inception_block not found") contract = vault.vault price_per_share = contract.getPricePerFullShare inception_price = 1e18 try: now_price = price_per_share(block_identifier=samples.now) except ValueError: now_price = inception_price if samples.week_ago > inception_block: try: week_ago_price = price_per_share(block_identifier=samples.week_ago) except ValueError: week_ago_price = now_price else: week_ago_price = now_price if samples.month_ago > inception_block: try: month_ago_price = price_per_share( block_identifier=samples.month_ago) except ValueError: month_ago_price = week_ago_price else: month_ago_price = week_ago_price now_point = SharePricePoint(samples.now, now_price) week_ago_point = SharePricePoint(samples.week_ago, week_ago_price) month_ago_point = SharePricePoint(samples.month_ago, month_ago_price) inception_point = SharePricePoint(inception_block, inception_price) week_ago_apy = calculate_roi(now_point, week_ago_point) month_ago_apy = calculate_roi(now_point, month_ago_point) inception_apy = calculate_roi(now_point, inception_point) # use the first non-zero apy, ordered by precedence apys = [week_ago_apy, month_ago_apy, inception_apy] net_apy = next((value for value in apys if value != 0), 0) strategy = vault.strategy withdrawal = strategy.withdrawalFee() if hasattr(strategy, "withdrawalFee") else 0 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 performance = (strategist_reward + strategist_performance + treasury) / 1e4 # assume we are compounding every week compounding = 52 # calculate our APR after fees # if net_apy is negative no fees are charged apr_after_fees = compounding * ( (net_apy + 1)** (1 / compounding)) - compounding if net_apy > 0 else net_apy # calculate our pre-fee APR gross_apr = apr_after_fees / (1 - performance) points = ApyPoints(week_ago_apy, month_ago_apy, inception_apy) fees = ApyFees(performance=performance, withdrawal=withdrawal) return Apy("v1:simple", gross_apr, net_apy, fees, points=points)