コード例 #1
0
 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
     ]
コード例 #2
0
ファイル: test_curve.py プロジェクト: yearn/yearn-exporter
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']))
コード例 #3
0
 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
     ]
コード例 #4
0
ファイル: v3.py プロジェクト: yearn/yearn-exporter
    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
コード例 #5
0
ファイル: fixed_forex.py プロジェクト: yearn/yearn-exporter
    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')
コード例 #6
0
ファイル: vaults_v1.py プロジェクト: kshilov/yearn-exporter
 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
コード例 #7
0
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)
コード例 #8
0
ファイル: events.py プロジェクト: kshilov/yearn-exporter
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})
コード例 #9
0
ファイル: tokenlist.py プロジェクト: kshilov/yearn-exporter
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}")
コード例 #10
0
 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
     ]
コード例 #11
0
ファイル: multicall2.py プロジェクト: yearn/yearn-exporter
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
コード例 #12
0
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
コード例 #13
0
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
コード例 #14
0
ファイル: tokenlist.py プロジェクト: yearn/yearn-exporter
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}")
コード例 #15
0
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)