예제 #1
0
def test_assets_static(ironBankAdapter):
    cyUsdcToken = Contract(cyUsdcAddress)
    usdcTokenAddress = ironBankAdapter.assetUnderlyingTokenAddress(
        cyUsdcAddress)

    cySushiToken = Contract(cySushiAddress)
    sushiTokenAddress = ironBankAdapter.assetUnderlyingTokenAddress(
        cySushiAddress)

    _, typeId, _ = ironBankAdapter.adapterInfo()
    usdcTokenName = cyUsdcToken.name()
    usdcTokenSymbol = cyUsdcToken.symbol()
    usdcTokenDecimal = cyUsdcToken.decimals()

    sushiTokenName = cySushiToken.name()
    sushiTokenSymbol = cySushiToken.symbol()
    sushiTokenDecimal = cySushiToken.decimals()

    assets = ironBankAdapter.assetsStatic([cyUsdcToken, cySushiToken])
    usdcAsset = assets[0]
    sushiAsset = assets[1]

    usdcAssetId = usdcAsset[0]
    usdcAssetTypeId = usdcAsset[1]
    usdcAssetTokenId = usdcAsset[2]
    usdcAssetName = usdcAsset[3]
    usdcAssetVersion = usdcAsset[4]
    usdcAssetSymbol = usdcAsset[5]
    usdcAssetDecimals = usdcAsset[6]

    assert usdcAssetId == cyUsdcAddress
    assert usdcAssetTypeId == typeId
    assert usdcAssetTokenId == usdcTokenAddress
    assert usdcAssetName == usdcTokenName
    assert usdcAssetVersion == "2.0.0"
    assert usdcAssetSymbol == usdcTokenSymbol
    assert usdcAssetDecimals == usdcTokenDecimal

    sushiAssetId = sushiAsset[0]
    sushiAssetTypeId = sushiAsset[1]
    sushiAssetTokenId = sushiAsset[2]
    sushiAssetName = sushiAsset[3]
    sushiAssetVersion = sushiAsset[4]
    sushiAssetSymbol = sushiAsset[5]
    sushiAssetDecimals = sushiAsset[6]

    assert sushiAssetId == cySushiAddress
    assert sushiAssetTypeId == typeId
    assert sushiAssetTokenId == sushiTokenAddress
    assert sushiAssetName == sushiTokenName
    assert sushiAssetVersion == "2.0.0"
    assert sushiAssetSymbol == sushiTokenSymbol
    assert sushiAssetDecimals == sushiTokenDecimal
예제 #2
0
def main():
    multi = MultiRewards.at(MULTIREWARDS_CONTRACT_ADDRESS)
    reward = Contract(REWARDTOKEN_CONTRACT_ADDRESS)

    # sanity check on the reward amount
    if REWARDS_AMOUNT < 10**reward.decimals():
        raise ValueError(
            "Reward amount is less than 1 token - are you sure this is correct?"
        )

    # ensure the reward admin has sufficient balance of the reward token
    if reward.balanceOf(REWARD_ADMIN) < REWARDS_AMOUNT:
        raise ValueError(
            "Rewards admin has insufficient balance to fund the contract")

    # ensure the reward contract has sufficient allowance to transfer the reward token
    if reward.allowance(REWARD_ADMIN, multi) < REWARDS_AMOUNT:
        reward.approve(multi, 2**256 - 1, {
            "from": REWARD_ADMIN,
            "gas_price": gas_strategy
        })

    # update the reward amount
    multi.notifyRewardAmount(reward, REWARDS_AMOUNT, {
        "from": REWARD_ADMIN,
        "gas_price": gas_strategy
    })

    print(
        f"Success! {REWARDS_AMOUNT/10**reward.decimals():.2f} {reward.symbol()} has been added"
    )
예제 #3
0
def main():
    token = Contract(REWARD_TOKEN_ADDRESS)
    seed_amount = 10 ** token.decimals()
    if token.balanceOf(REWARD_ADMIN) < seed_amount:
        raise ValueError("Reward admin must have at least 1 token to seed the contract for testing")

    # deploy the rewards contract - initially we set the reward period to one day so we
    # can seed a small amount for testing
    rewards = StakingRewards.deploy(
        OWNER,
        REWARD_ADMIN,
        token,
        STAKING_TOKEN_ADDRESS,
        86400,
        {'from': DEPLOYER, 'gas_price': gas_strategy}
    )

    # give infinite approval to the reward contract from the reward admin
    token.approve(rewards, 2**256-1, {'from': REWARD_ADMIN, 'gas_price': gas_strategy})

    # seed the contract with 1 token for initial testing
    rewards.notifyRewardAmount(seed_amount, {'from': REWARD_ADMIN, 'gas_price': gas_strategy})

    print(f"""Success!

StakingRewards deployed to: {rewards}
Owner: {OWNER}
Reward admin: {REWARD_ADMIN}

Please verify the source code on Etherscan here: https://etherscan.io/verifyContract?a={rewards}
Compiler version: 0.5.17
Optimization: ON
""")
예제 #4
0
def test_asset_static(ironBankAdapter):
    cyUsdcToken = Contract(cyUsdcAddress)
    usdcTokenAddress = ironBankAdapter.assetUnderlyingTokenAddress(
        cyUsdcAddress)
    _, typeId, _ = ironBankAdapter.adapterInfo()
    usdcTokenName = cyUsdcToken.name()
    usdcTokenSymbol = cyUsdcToken.symbol()
    usdcTokenDecimal = cyUsdcToken.decimals()

    assetStatic = ironBankAdapter.assetStatic(cyUsdcAddress)
    assetId = assetStatic[0]
    assetTypeId = assetStatic[1]
    assetTokenId = assetStatic[2]
    assetName = assetStatic[3]
    assetVersion = assetStatic[4]
    assetSymbol = assetStatic[5]
    assetDecimals = assetStatic[6]

    assert assetId == cyUsdcAddress
    assert assetTypeId == typeId
    assert assetTokenId == usdcTokenAddress
    assert assetName == usdcTokenName
    assert assetVersion == "2.0.0"
    assert assetSymbol == usdcTokenSymbol
    assert assetDecimals == usdcTokenDecimal
예제 #5
0
class Earn:
    def __init__(self, name, vault):
        self.name = name
        self.vault = Contract(vault)
        self.token = self.vault.token()
        self.scale = 10**self.vault.decimals()

    def __repr__(self) -> str:
        return f"Earn({repr(self.name)}, {repr(self.vault.address)})"
예제 #6
0
def _get_admin_balances(pool):
    admin_balances = []

    for i in range(8):
        try:
            coin = Contract(pool.coins(i))
            if hasattr(pool, "admin_balances"):
                balance = pool.admin_balances(i)
            else:
                balance = coin.balanceOf(pool) - pool.balances(i)
            balance = balance / 10**coin.decimals() * _fetch_rate(coin)
            admin_balances.append(balance)

        except Exception:
            return admin_balances
예제 #7
0
def main():
    rewards = StakingRewards.at(REWARDS_CONTRACT_ADDRESS)
    token = Contract(rewards.rewardsToken())

    # sanity check on the reward amount
    if REWARDS_AMOUNT < 10**token.decimals():
        raise ValueError(
            "Reward amount is less than 1 token - are you sure this is correct?"
        )

    # ensure the reward admin has sufficient balance of the reward token
    if token.balanceOf(REWARD_ADMIN) < REWARDS_AMOUNT:
        raise ValueError(
            "Rewards admin has insufficient balance to fund the contract")

    # check the reward duration and modify if needed
    if rewards.rewardsDuration() != REWARDS_DURATION:
        remaining_time = rewards.periodFinish() - chain[-1].timestamp
        if remaining_time > 0:
            raise ValueError(
                "Current reward period must finish before the period duration can be modified, "
                f"try again in {datetime.timedelta(seconds=remaining_time)}")
        rewards.setRewardsDuration(REWARDS_DURATION, {'from': OWNER})

    # ensure the reward contract has sufficient allowance to transfer the reward token
    if token.allowance(REWARD_ADMIN, rewards) < REWARDS_AMOUNT:
        token.approve(rewards, 2**256 - 1, {
            'from': REWARD_ADMIN,
            'gas_price': gas_strategy
        })

    # update the reward amount
    rewards.notifyRewardAmount(REWARDS_AMOUNT, {
        'from': REWARD_ADMIN,
        'gas_price': gas_strategy
    })

    print(
        f"Success! {REWARDS_AMOUNT/10**token.decimals():.2f} {token.symbol()} has been added to "
        f"the rewards contract, to be distributed over {REWARDS_DURATION/86400:.1f} days."
    )
예제 #8
0
class VaultV1:
    vault: InterfaceContainer
    controller: InterfaceContainer
    token: interface.ERC20
    strategy: str
    is_wrapped: bool
    is_delegated: bool
    # the rest is populated in post init
    name: Optional[str] = None
    decimals: Optional[int] = None

    def __post_init__(self):
        self.vault = Contract(self.vault)
        self.controller = Contract(self.controller)
        self.strategy = Contract(self.strategy)
        self.token = Contract(self.token)
        if str(self.vault) not in constants.VAULT_ALIASES:
            logger.warning(
                "no vault alias for %s, reading from vault.sybmol()",
                self.vault)
        self.name = constants.VAULT_ALIASES.get(str(self.vault),
                                                self.vault.symbol())
        self.decimals = self.vault.decimals(
        )  # vaults inherit decimals from token
        self.scale = 10**self.decimals

    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)

    def get_strategy(self, block=None):
        if self.name in ["aLINK", "LINK"]:
            return self.strategy
        strategy = self.controller.strategies(self.token,
                                              block_identifier=block)
        return Contract(strategy)

    def describe(self, block=None):
        info = {}
        strategy = self.strategy
        if block is not None:
            strategy = self.get_strategy(block=block)

        # attrs are fetches as multicall and populate info
        attrs = {
            "vault balance": [self.vault, "balance"],
            "vault total": [self.vault, "totalSupply"],
            "strategy balance": [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(strategy, "proxy"):
            vote_proxy, gauge = fetch_multicall(
                [strategy, "voter"],  # voter is static, can pin
                [strategy, "gauge"],  # gauge is static per strategy, can cache
                block=block,
            )
            vote_proxy = interface.CurveYCRVVoter(vote_proxy)
            gauge = Contract(gauge)
            info.update(curve.calculate_boost(gauge, vote_proxy, block=block))
            info.update(curve.calculate_apy(gauge, self.token, block=block))
            attrs["earned"] = [gauge, "claimable_tokens",
                               vote_proxy]  # / scale

        if hasattr(strategy, "earned"):
            attrs["lifetime earned"] = [strategy, "earned"]  # /scale

        if strategy._name == "StrategyYFIGovernance":
            ygov = interface.YearnGovernance(strategy.gov())
            attrs["earned"] = [ygov, "earned", strategy]
            attrs["reward rate"] = [ygov, "rewardRate"]
            attrs["ygov balance"] = [ygov, "balanceOf", strategy]
            attrs["ygov total"] = [ygov, "totalSupply"]

        # fetch attrs as multicall
        results = fetch_multicall(*attrs.values(), block=block)
        for name, attr in zip(attrs, results):
            if attr is not None:
                info[name] = attr / self.scale
            else:
                logger.warning("attr %s rekt %s", name, attr)

        # some additional post-processing
        if "min" in info:
            info["strategy buffer"] = info.pop("min") / info.pop("max")

        if "token price" not in info:
            info["token price"] = self.get_price(block=block)

        info["tvl"] = info["vault balance"] * info["token price"]

        return info
def test_clone(
    vault,
    strategy,
    strategist,
    rewards,
    keeper,
    gov,
    token,
    token_whale,
    borrow_token,
    borrow_whale,
    yvault,
    cloner,
):
    pd_provider = Contract("0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d")
    a_provider = Contract(pd_provider.ADDRESSES_PROVIDER())
    lp = Contract(a_provider.getLendingPool())
    vault_snx = Contract("0xF29AE508698bDeF169B89834F76704C3B205aedf")
    snx = Contract(vault_snx.token())
    snx_whale = "0xA1d7b2d891e3A1f9ef4bBC5be20630C2FEB1c470"
    clone_tx = cloner.cloneAaveLenderBorrower(
        vault,
        strategist,
        rewards,
        keeper,
        vault_snx,
        True,
        False,
        "StrategyAaveLender" + token.symbol() + "BorrowerSNX",
    )
    cloned_strategy = Contract.from_abi("Strategy",
                                        clone_tx.events["Cloned"]["clone"],
                                        strategy.abi)

    cloned_strategy.setStrategyParams(
        strategy.targetLTVMultiplier(),
        strategy.warningLTVMultiplier(),
        strategy.acceptableCostsRay(),
        0,
        strategy.maxTotalBorrowIT(),
        strategy.isWantIncentivised(),
        False,  # snx is not incentivised
        strategy.leaveDebtBehind(),
        strategy.maxLoss(),
        strategy.maxGasPriceToTend(),
        {"from": strategy.strategist()},
    )

    uniswap = Contract("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D")
    cloned_strategy.switchDex(True, {"from": gov})
    assert cloned_strategy.router() == uniswap

    # should fail due to already initialized
    with reverts():
        strategy.initialize(vault, vault_snx, "NameRevert", {"from": gov})

    vault.updateStrategyDebtRatio(strategy, 0, {"from": gov})
    vault.addStrategy(cloned_strategy, 10_000, 0, 2**256 - 1, 0, {"from": gov})

    token.approve(vault, 2**256 - 1, {"from": token_whale})
    vault.deposit(10 * (10**token.decimals()), {"from": token_whale})
    strategy = cloned_strategy
    print_debug(vault_snx, strategy, lp)
    tx = strategy.harvest({"from": gov})
    assert vault_snx.balanceOf(strategy) > 0
    print_debug(vault_snx, strategy, lp)

    # Sleep for 2 days
    chain.sleep(60 * 60 * 24 * 2)
    chain.mine(1)

    # Send some profit to yvETH
    snx.transfer(vault_snx, 1_000 * (10**snx.decimals()), {"from": snx_whale})

    # TODO: check profits before and after
    strategy.harvest({"from": gov})
    print_debug(vault_snx, strategy, lp)

    # We should have profit after getting some profit from yvETH
    assert vault.strategies(strategy).dict()["totalGain"] > 0
    assert vault.strategies(strategy).dict()["totalLoss"] == 0

    # Enough sleep for profit to be free
    chain.sleep(60 * 60 * 10)
    chain.mine(1)
    print_debug(vault_snx, strategy, lp)

    # why do we have losses? because of interests
    with reverts():
        vault.withdraw()

    # so we send profits
    snx.transfer(vault_snx, Wei("30_000 ether"), {"from": snx_whale})
    vault.withdraw({"from": token_whale})
예제 #10
0
def test_asset_positions_of(ironBankAdapter, accounts):

    weth = Contract(wethAddress)
    cyWeth = Contract(cyWethAddress)
    user = accounts.at(userAddress, force=True)
    MAX_UINT256 = 2**256 - 1
    weth.approve(cyWeth, MAX_UINT256, {"from": user})
    weth_bal = weth.balanceOf(userAddress)
    cyWeth.mint(weth_bal, {"from": user})

    comptroller = Contract(comptrollerAddress)

    comptroller.enterMarkets([cyWeth], {"from": user})

    cyWeth = Contract(cyWethAddress)
    cyWethTokenAddress = ironBankAdapter.assetUnderlyingTokenAddress(
        cyWethAddress)
    cyWethTokenPrice = ironBankAdapter.assetUnderlyingTokenPriceUsdc(
        cyWethAddress)
    decimal = cyWeth.decimals()

    userSupplyBalanceShares = cyWeth.balanceOf(userAddress)
    userBorrowBalanceShares = cyWeth.borrowBalanceStored(userAddress)
    assert userSupplyBalanceShares > 0
    assert userBorrowBalanceShares > 0

    exchangeRate = cyWeth.exchangeRateStored()

    userSupplyBalanceUnderlying = userSupplyBalanceShares * exchangeRate / 10**18

    positions = ironBankAdapter.assetPositionsOf(userAddress, cyWethAddress)
    assert userSupplyBalanceUnderlying > 0
    # print(positions)
    supplyPosition = positions[0]

    # basic info test
    assetId = supplyPosition[0]
    tokenId = supplyPosition[1]
    typeId = supplyPosition[2]
    balance = supplyPosition[3]
    # print(assetId, tokenId, typeId, balance)
    assert assetId == cyWethAddress
    assert tokenId == cyWethTokenAddress
    assert typeId == "LEND"
    assert balance == userSupplyBalanceShares

    # Test token allowances
    tokenAllowances = supplyPosition[5]
    owner = tokenAllowances[0][0]
    spender = tokenAllowances[0][1]
    allowance = tokenAllowances[0][2]
    assert owner == userAddress
    assert spender == cyWethAddress
    assert allowance > 0

    # Test account borrow balance
    userBorrowedCyTokenBalance = userBorrowBalanceShares * 10**18 / exchangeRate

    borrowPosition = positions[1]

    # basic info test
    assetId = borrowPosition[0]
    tokenId = borrowPosition[1]
    typeId = borrowPosition[2]
    balance = borrowPosition[3]
    # print(assetId, tokenId, typeId, balance)
    assert assetId == cyWethAddress
    assert tokenId == cyWethTokenAddress
    assert typeId == "BORROW"
    assert balance == userBorrowedCyTokenBalance

    # Test token allowances
    tokenAllowances = borrowPosition[5]
    owner = tokenAllowances[0][0]
    spender = tokenAllowances[0][1]
    allowance = tokenAllowances[0][2]
    assert owner == userAddress
    assert spender == cyWethAddress
    assert allowance > 0